2014年8月12日 星期二

jQuery Mobile 載入新頁面

使用 jQuery Mobile 時,jQuery Mobile 預設是用 ajax 載入頁面的內容,所以使用連結或送出

表單到另一個頁面應是把 <body> 裡的資料載入呈現,body 以外的 script, js, css 不會再被重

新要求載入、執行。


測試程式碼:

<body>
    <div>
        <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
            <li><a href="link2.html">link2</a></li>                
        </ul>
        <a href="link2.html" data-role="none">link2</a>
    </div>
</body>

測試程式碼二:

<script type="text/javascript">
    $(document).ready(function() {
        alert('test');
    });
</script>

<body>
    <div>link test</div>
</body>
(script 放在 head 的 tag 之間)

(以上程式碼要在 head 引入 jQuery Mobile 的 js code)


 
(利用程式碼一連結程式碼二的頁面) 

(用 chrome 的 network 看,有載入所用到的檔案)


(程式碼二的 script 不會被執行) 

 (不會再載入用到的 script)


測試:

把 script 放在 body 裡時,script 有被執行,但是放在 body 之外的其他地方,script 不會被執

行,推測應該是只把 body 裡的程式碼載入呈現。



解決辦法:

關閉 jQuery Mobile 預設的 ajax:在 <a>、<form> 裡加入 data-ajax="false"。

修改程式碼一

<body>
    <div>
        <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
            <li><a href="link2.html" data-ajax="false">link2</a></li>                
        </ul>
        <a href="link2.html" data-role="none" data-ajax="false">link2</a>
    </div>
</body>

(script 成功被執行)

2014年8月6日 星期三

Yii2 registerJs

registerJs 可以用來插入 script,並設定插入位置、執行時機。

registerJs( $js, $position, $identified_name );

$js : 放入 script

$position :

有五種 : POS_HEAD、POS_BEGIN、POS_END、POS_READY、POS_LOAD

POS_HEAD:放在 <head> 和 </head> 之間

POS_BEGIN:放在 <body> 的一開始

                           ex : <body>
                                      <script type="text/javascript">
                                          ...
                                      </script>

                                      HTML....
                                  </body>

POS_END:放在 <body> 的最後 ( </body> 前 )

                           ex : <body>
                                      HTML....

                                      <script type="text/javascript">
                                          ...
                                      </script>
                                  </body>

POS_READY:測試時,發現放的位置和 POS_END 一樣

                            但所設定的 script 會放在 jQuery(document).ready(fuction(){ ... }); 裡

                           ex : <body>
                                      HTML....

                                      <script type="text/javascript">
                                         
                     jQuery(document).ready(function () {
                         ...
                     });
                                      </script>
                                  </body>

                           ready : 等到 HTML 的 tag 都產生後才執行 script,因為 script 裡面可能會有想

                                       要抓取 tag、對 tag 做設定,所以要等 tag 產生,否則 script 在執行時

                                       會有問題 。


POS_LOAD:測試時,發現放的位置和 POS_END 一樣

                          但所設定的 script 會放在 jQuery(window).load(fuction () { ... }); 裡

                           ex : <body>
                                      HTML....

                                      <script type="text/javascript">
                                         
                     jQuery(window).load(function () {
                         ...
                     });
                                      </script>
                                  </body>

                           load : 會等到所有網頁的資源都下載完後才執行 script,因為 scirpt 裡面可能

                                     會有想要抓取這些資源的資訊,所以要等這些資源下載完,否則 script

                                     在執行時會有問題。

                                     資源:ex : 圖片、flash、iframe

$identified_name : 

設定這組註冊 script 的名稱,預設為 null。如果有兩個註冊的名稱相同,後面的會覆蓋前面的

script。



使用前:

regitserJs 是放在 yii\web\View 裡面,如果要方便使用的話,可以先

use yii\web\View;

之後就可以 $this->registerJs( ... );


使用範例:

use yii\web\View;

$this->registerJs(

          "alert( "registerJs test" );" ,

          POS_HEAD,

          null
);

2014年7月25日 星期五

uva 10340 All in All

只要確定是否有一組 subsequence 為 sequence 即可,只要走訪一次被尋找的 string,當發現

有相同的字元時,就找下一個 sequence 的字元。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    char input[1000000],target[1000000];
    int i,j,k,outcome;

    while(scanf("%s %s",&target,&input)!=EOF){
        outcome=0;

        k=0;
        for(i=0;i<strlen(input);i++){

            if(target[k]==input[i]) k++;

            if(target[k]=='\0'){
                outcome=1;
                break;
            }
        }

        if(outcome==1){
            printf("Yes\n");
        }else{
            printf("No\n");
        }
    }



    return 0;
}

uva 10079 Pizza Cutting

把 0 ~ 10 計算出來就會比較有感覺,他是有個規律在。

0 : 1
1 : 2
2 : 4
3 : 7
4 : 11
5 : 16
6 : 22
7 : 29
8 : 37
9 : 46
10 : 56

從上面可以發現,下一個的塊數為上一個的塊數 + 這次的直線數量

如果接下來都是這樣,可以歸納出一個公式 : ( n ^ 2 + n ) / 2 + 1


接下來都會符合,因為:

最大塊數和這條直線可以在上一個最大塊數的情況下最多可以經過幾個區塊,每經過一個區

塊,就會多切出一塊;

最多可以經過幾個區塊跟上一個的直線數有關,區塊和區塊之間是由線分隔,兩條線最多只

會有一個交點,區塊之間由交點分隔,區塊 = 交點數 + 1,最多交點數為上一個的直線數。

Sn : n 條線最多可以切出的塊數

Sn = Sn-1 + n  => ( n ^ 2 + n ) / 2 + 1


注意:測資大小的範圍 : 0 <= N <= 210000000 => 可用 long long int

long long int 如果在 windows 下跑  210000000出現 overflow 的情況,這是因為環境的問

題,judge 的環境,long long int 可以處理這麼大的數字的。


#include <stdio.h>
#include <stdlib.h>

int main(void){
    long long int line;

    while(scanf("%lld",&line)!=EOF){
        if(line < 0) break;

        printf("%lld\n", ( (line*line+line)/2 + 1 ) );
    }

    return 0;
}

2014年7月23日 星期三

uva 424 Integer Inquiry

實做加法的大數運算:

如果直接把讀到的數字做加法,需要考慮位數對應和擴增陣列大小的問題。

把所有讀到的數字反向,再做加法 => 位數直接對應,擴增大小只要往後面加數字即可。

輸出結果時,再反向回來即可。

注意:

1. 如果用 fgets 讀,會有 '\n',改用 scanf("%s") 可以避免這個問題。

2.  當新加的數字位數比目前的 sum 多,或是兩個數字相加後,超過目前的位數時,需要對

    sum 擴增,因為 sum 擴增的那一位的值 0,跟原本兩個字元做相加的運算不同,所以要寫

   判斷式處理。

   ex :

   num[10]={0};

   假設現在 num 讀到 956 (第一個數字)

   下一個數字為 956

      659
    +659
________
      2191
            ↑ 在 num 裡原本的值是 0,如果依照前面字元 num[i]+= '9' - '0' + carry 的方法處理,

               在 if( num[i] > '9' ) 判斷進位的地方會有問題,所以遇到原本的值為 0 時,直接把値

               存進去 num[i] = carry + '0'
       6
     +05
________
       65
         ↑ 這個情況也是,原本的值是 0,直接把直存進去 num[i] = num_tmp[i] + carry



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void reverNum(char number[]){
    char tmp[150]={0};
    int i,j;

    for(i=strlen(number)-1,j=0;i>=0;i--,j++){
        tmp[j]=number[i];
    }
    tmp[j]='\0';

    for(i=0;tmp[i]!='\0';i++){
        number[i]=tmp[i];
    }

    return;
}

int main(void){
    char number[150]={0},number_tmp[150]={0},carry;
    int i,top;

    top=-1;

    fgets(number,150-1,stdin);
    number[strlen(number)-1]='\0';
    reverNum(number);

    while( fgets(number_tmp,150-1,stdin)!=NULL ){
        if( strlen(number_tmp)==2 && number_tmp[0]=='0' ){
            break;
        }
        number_tmp[strlen(number_tmp)-1]='\0';
        reverNum(number_tmp);

        carry=0;
        for(i=0;number_tmp[i]!='\0';i++){
            if(number[i]==0){
                number[i] = number_tmp[i] + carry;
            }else{
                number[i] += (number_tmp[i]-'0') + carry;
            }

            if(number[i] > '9'){
                carry=(number[i]-'0')/10;
                number[i] = ( (number[i]-'0') % 10 ) + '0';
            }else{
                carry=0;
            }
        }

        while(carry!=0){
            if(number[i]==0){
                number[i]=carry+'0';
            }else{
                number[i]+=carry;
            }

            if(number[i] > '9'){
                carry=(number[i]-'0')/10;
                number[i] = ( (number[i]-'0') % 10 ) + '0';
            }else{
                carry=0;
            }

            ++i;
        }
    }

    reverNum(number);

    printf("%s\n",number);

    return 0;
}

2014年7月22日 星期二

uva 10041 Vito's Family

一看到題目時,會想說把 street number 全加起來後算總共相異 street number 個數的平均,

但是取 street number 的中位數所得的 sum 會更少。

平均數為這些 street number 的中心,和左、右的 street number的差異在 +1 ~ -1 之間,但

是題目有說 "會有相同的 street number",平均數左、右兩邊的 street number 個數不相同,

加總起來時,會因為相同的 street number,而造成差異。

中位數的兩邊的 street number 個數都一樣,即使完全相異的 street number 也可以處理。

ex: 2, 3, 10

mean : 5   =>   2, 3, 5, 10

5 向左、右兩邊走時,都要走 d(3,5), d(3,10)

median : 3 => 2, 3, 10

往右走時,會走 d(3,10)

d(3,10) < d(3,5) + d(3,10)

當數字有出現相同時,中位數的某一邊 street number 個數有可能比較多,造成 sum 增加。

因此,取中位數所得的 sum 會比較小。


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int compare(const void* a , const void* b){
    return *(int *)a - *(int *)b;
}

int main(void){
    int amount,i;
    int relatives,streets[510],sum,median;

    scanf("%d",&amount);
    while(amount--){
        scanf("%d",&relatives);
        for(i=0;i<relatives;i++){
            scanf("%d",&streets[i]);
        }

        qsort(streets,relatives,sizeof(int),compare);

        median=streets[relatives/2];

        sum=0;
        for(i=0;i<relatives;i++){
            sum+=abs(streets[i]-median);
        }

        printf("%d\n",sum);
    }



    return 0;
}

2014年7月16日 星期三

uva 657 The die is cast

解析圖 (travel graph),實作時,比較難判斷的是遇到的 "X" 是否是和其他 "X" 相連,可能是從

其他方向走道 "X",但是這是和之前走過的 "X" 相連。
 
我用的是兩個不同功能的 DFS,一個是用來把相連的 " *" 走完,一個是用來走完相連的一組

"X",因為相連的 "X",代表要被計算的點數值 1,但是走過的 "X" 要標上 "*",前一個 DFS 才

能把這面 dice 走完。一次直接把連接的 "X" 走完,那下次遇到的 "X" 一定不是和之前遇到的

"X" 相連的,會比較好判斷。


test input:
3 2
XX*
X..
0 0

test output:
Throw 1
1
(newline)

(test input , output from : http://acm.uva.es/board/viewtopic.php?f=7&t=1948&hilit=657&sid=e5ead96b6830e0b0e7baed52294a391e&start=30#p204733)


#include <stdio.h>
#include <stdlib.h>

int counter;
int w,h;
char dice[60][60]={0};

void DFS_X(int x,int y){
    if(dice[x][y]!='X') return;

    dice[x][y]='*';

    DFS_X(x+1,y);
    DFS_X(x,y+1);
    DFS_X(x-1,y);
    DFS_X(x,y-1);

    return;
}

void DFS(int x, int y){
    if(dice[x][y]!='*' && dice[x][y]!='X') return;


    if(dice[x][y]=='X'){
        ++counter;
        DFS_X(x,y);
    }

    dice[x][y]='.';

    DFS(x+1,y);
    DFS(x,y+1);
    DFS(x-1,y);
    DFS(x,y-1);

    return;
}

int compare(const void*a, const void*b){
    return (*(int*)a)-(*(int*)b);
}

int main(void){
    int i,j;
    int num[100],top,cases=0;
    char c;

    while(scanf("%d%d%c",&w,&h,&c)==3){
        if(!w&&!h) break;

        for(i=1;i<=h;i++){
            for(j=1;j<=w;j++){
                scanf("%c",&dice[i][j]);
            }
            scanf("%c",&dice[i][j]);
        }

        top=-1;
        for(i=1;i<=h;i++){
            for(j=1;j<=w;j++){
                if(dice[i][j]=='*' || dice[i][j]=='X'){
                    counter=0;
                    DFS(i,j);
                    num[++top]=counter;
                }
            }
        }
        qsort(num,top+1,sizeof(int),compare);

        printf("Throw %d\n",++cases);
        for(i=0;i<top;i++){
            printf("%d ",num[i]);
        }
        printf("%d\n\n",num[i]);


    }


    return 0;
}



uva 483 Word Scramble

一次讀整的字串,用 strtok 把一個一個字串切出來,在反向印出。

注意:newline 遇到時,要等最後這一個子字串印完後再印。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    char input[1000];
    char *part;
    int i;

    while(fgets(input,1000-1,stdin)!=NULL){
        part=strtok(input," ");
        while(part!=NULL){
            for(i=strlen(part)-1 ; i>=0 ; i--){
                if(part[i]=='\n') continue;
                printf("%c",part[i]);
            }

            part=strtok(NULL," ");
            if(part!=NULL) printf(" ");
        }
        printf("\n");

    }

    return 0;
}

uva 575 Skew Binary

把字串讀進來, 按照每個 digit 的權重做計算即可。

注意:如果是讀整個字串進來,至少長度為 2,因為有 newline。


#include <stdio.h>
#include <stdlib.h>

int main(void){
    char input[100];
    int base,num,i;

    while(fgets(input,100-1,stdin)!=NULL){
        /* consider newline => strlen at least 2 */
        if(strlen(input)==2 && input[0]=='0') break;

        num=0; base=2;
        for(i=strlen(input)-2 ; i>=0 ; i--, base*=2){
            num += (base-1) * (input[i]-'0');
        }

        printf("%d\n",num);
    }


    return 0;
}

uva 10666 The Eurocup is Here!

這題試著把 round 3 的情形 (每一個都看過) 和測資的範例走過一遍後,會很清楚怎麼運作,

並會把所有情形考慮到。

要得知一個 number的 optimistic classification 和 pessimistic classification,分別需要知道此

number確定輸過幾個 numbers 和確定贏過幾個 numbers。

確定輸過幾個 numbers:因為 transitivity,所以在某個 round 輸了,後面的 round 也都代表自

 己輸了。要求 optimistic classification,可以當成自己只有輸過這些 numbers,其他 numbers

都假設贏了,所以 optimistic classification 下的 rank 為確定輸的 number 數 + 1。

確定贏過幾個 numbers:總 number 數 - 確定贏了幾個 numbers。因為 transitivity,所以在某

個 round 贏了之後,自己也贏了這個之下的所有 numbers。確定贏了幾個 number 之

後,optimistic classification 下的 rank 就不會比這些 number 低,所以 rank= 總 number 數 - 

確定贏了幾個 numbers。(可用記錄數字贏到第幾 round => 此 round 下面的數字都贏:2^N -1 

個)


#include <stdio.h>
#include <stdlib.h>

int main(void){
    int win_num,win,lose,component,base,round;
    int i,amount;

    scanf("%d",&amount);
    while(amount--){
        scanf("%d %d",&round,&win_num);

        base=1;
        lose=win=0;
        for(i=0;i<round;i++,base*=2){
            component=( ( (win_num/base)%2 ) == 0 ) ? (win_num + base) : (win_num - base);

            if(lose==0){
                if(win_num > component){
                    ++lose;
                    win_num=component;
                }else{
                    ++win;
                }
            }else{
                if(win_num > component){
                    ++lose;
                    win_num=component;
                }
            }
        }
        win=pow(2,win)-1;

        printf("%d %d\n",lose+1,base-win);
    }




    return 0;
}

2014年7月15日 星期二

uva 10004 Bicoloring

用 adjacent list 把圖存好後,走一次圖,可以採用 BFS,先把第一個 node 塗上顏色,用此點

開始走,鄰居塗上和自己不同的顏色,如果發現鄰居已經有顏色了,判斷是否相同顏色,相

同 => notbicolorable,不相同 => OK


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int maps[201][201];

int BFS(){
    int i,ok;
    int queueList[201]={0},top,head,extract,neighbor;
    int color[201]={0}; /* color : 1, 2 */

    ok=1;

    head=top=0;
    queueList[top]=1; color[1]=1;
    while(head<=top){
        extract=queueList[head++];

        for(i=1;i<=maps[extract][0];i++){
            neighbor=maps[extract][i];

            if(color[neighbor]==0){
                color[neighbor]= (color[extract]==1) ? 2 : 1;
                queueList[++top]=neighbor;
            }else if(color[neighbor] == color[extract]){
                ok=0;
                head=top+1; /* break while */
                break;
            }
        }
    }

    return ok;
}

int main(void){
    int nodes,edges;
    int i,src,dest,outcome;


    while(scanf("%d",&nodes)!=EOF){
        if(!nodes) break;

        scanf("%d",&edges);

        memset(maps,0,sizeof(maps));
        for(i=0;i<edges;i++){
            scanf("%d %d",&src,&dest);
            maps[src+1][++maps[src+1][0]]=dest+1;
            maps[dest+1][++maps[dest+1][0]]=src+1;
        }

        outcome=BFS();

        if(outcome==1)
            printf("BICOLORABLE.\n");
        else
            printf("NOT BICOLORABLE.\n");
    }

    return 0;
}

uva 10110 Light, more light

blub 的開關被操作偶數次,最後會是關閉的,被操作奇數次,最後會是開啟的。

當發現數字的其中一個因數時,通常是成對出現的,除了完全平方數,所以只有完全平方數

是的因數會是奇數。

判斷是否為完全平方數時,因為 sqrt 回傳的是 double,如果用 int 的變數接的話,會有誤差

(用 int 是為了用 % 看此數的平方根數否為此數的因數),所以用 floor 和 ceil 確認,如果兩個

值相等,表示是完全平方數。

(本來一開始是從 1 到數字的平方根之間找因數,計算因數的個數,但是造成 TLE,floor 和 ceil 方法學習自 : http://acm.uva.es/board/viewtopic.php?f=10&t=10656&p=128846&hilit=10110&sid=48865e44dcc662d2e49822799291e900#p110511)


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
    double num;

    while(scanf("%lf",&num)!=EOF){
        if(!num) break;

        if( floor(sqrt(num)) == ceil(sqrt(num)) ){
            printf("yes\n");
        }else{
            printf("no\n");
        }
    }

    return 0;
}

2014年7月14日 星期一

uva 11917 Do Your Own Homework

讀取的時候使用 scanf("%s %d",&course[i],&day[i]);  (course 要宣告成二維陣列)會方便許多。

course 儲存時,是 course[i] 的位置開始存,存到 course[ i ] [ 0 ] ~ course[ i ] [ j ]

其他的依照題目的意思比較即可。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
    int amount,subject,i,cases=0;
    char course[100][100];
    int day[100];

    int due;
    char hw[30];

    int ok;

    scanf("%d",&amount);
    while(amount--){
        scanf("%d",&subject);

        for(i=0;i<subject;i++){
            scanf("%s %d",&course[i],&day[i]);
        }

        scanf("%d%s",&due,&hw);



        ok=0;
        for(i=0;i<subject;i++){
            if(strcmp(course[i],hw)==0){
                if(day[i]<=due){
                    printf("Case %d: Yesss\n",++cases);
                }else if(day[i] <= due+5){
                    printf("Case %d: Late\n",++cases);
                }else{
                    printf("Case %d: Do your own homework!\n",++cases);
                }

                ok=1;
                break;
            }
        }

        if(ok==0)
            printf("Case %d: Do your own homework!\n",++cases);
    }



    return 0;
}

uva 10235 Simply Emirp

注意:1. 若質數 reverse 的數字和原本的數字相同,此質數不是 emirp。

            2. 1 和 0 不是質數

 
test input:

999
481184
373
998001
998857
753257
823455
999999
850058
78887
999983


test output:

999 is not prime.
481184 is not prime.
373 is prime.
998001 is not prime.
998857 is emirp.
753257 is prime.
823455 is not prime.
999999 is not prime.
850058 is not prime.
78887 is prime.
999983 is emirp.
 


(test input, output from : http://acm.uva.es/board/viewtopic.php?f=38&t=76675&p=368862&hilit=10235&sid=abfeae4866641eb3eff8acaf0850d1e2#p368862) 


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int prime(int num){
    int limit;
    int i;

    if(num==1 || num == 0) return 0;

    limit=sqrt(num);

    for(i=2;i<=limit;i++){
        if(num%i==0)
            return 0;
    }
    return 1;
}

int emirp(int num){
    char rever[1000000]={0};
    int i=0;
    int num2;

    if(num < 13) return 0;

    num2=num;
    while(num2!=0){
        rever[i++]=(num2%10)+'0';
        num2/=10;

    }
    rever[i]='\0';
    num2=atoi(rever);

    if(num==num2) return 0;

    if(prime(num2)==1)
        return 1;
    else
        return 0;
}

int main(void){

    int n;

    while(scanf("%d",&n)!=EOF){
        if(n==1 || n==0){
            printf("%d is not prime.\n",n);
            continue;
        }

        if(prime(n)==1){
            if(emirp(n)){
                printf("%d is emirp.\n",n);
            }else{
                printf("%d is prime.\n",n);
            }
        }else{
            printf("%d is not prime.\n",n);
        }
    }

    return 0;
}

uva 12602 Nice Licence Plates

按照題目的算法計算即可。


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
    int amount,i;
    char plate[10],c1,c2,c3,c;
    int first,second;

    scanf("%d%c",&amount,&c);
    while(amount--){
        scanf("%c%c%c%c%d%c",&c1,&c2,&c3,&c,&second,&c);
        first=(c1-'A')*26*26+(c2-'A')*26+(c3-'A');

        if(abs(first-second)<=100)
            printf("nice\n");
        else
            printf("not nice\n");
    }

    return 0;
}

uva 10008 What's Cryptanalysis

用陣列計算字母出現的次數,並把第一次出現的字母存到另一個陣列,在 sort 和顯示時,可

以用來做 map。

注意:qsort 的 compare function 的 return value,value < 0 : 不交換,value >= 0 : 交換。


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int alphabet[300]={0};

int compare(const void *a, const void*b){
    int aa,bb;
    aa=*(int*)a;
    bb=*(int*)b;

    if(alphabet[aa] < alphabet[bb]){
        return 1;
    }else if(alphabet[aa] == alphabet[bb]){
        if(aa > bb) return 1;
    }

    return -1;
}

int main(void){
    int lines,i,j,tmp;
    char input[10000],c;
    int order[26],top;

    while(scanf("%d%c",&lines,&c)!=EOF){
        memset(alphabet,0,sizeof(alphabet));
        top=-1;

        for(i=0;i<lines;i++){
            fgets(input,10000-1,stdin);
            for(j=0;input[j]!='\n';j++){
                tmp=toupper(input[j]);
                if(tmp >= 'A' && tmp <='Z'){
                    ++alphabet[tmp];

                    if(alphabet[tmp]==1){
                        order[++top]=tmp;
                    }
                }
            }
        }

        qsort(order,top+1,sizeof(int),compare);

        for(i=0;i<=top;i++){
            printf("%c %d\n",order[i],alphabet[order[i]]);
        }
    }


    return 0;
}

uva 579 Clock Hands

統一以 12 點為基準去計算角度:

分針走一格 => 1 min => 時針走 0.5 度

時鐘上一格 6 度。

ex: 8:10
(先不考慮分針對時針的影響)
hour : 8 -> 8 * 5 * 6 = 240 度
min : 10 -> 10* 6 = 60 度                =>   hour : 240 + 10 * 0.5 = 245 度

245 - 60 = 185 (轉換成最小正角度) => 360 - 185 = 175 度


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
    int h,m;
    char input[10]={0};
    double degree,hD,mD;

    while(fgets(input,10-1,stdin)!=NULL){
        sscanf(input,"%d:%d",&h,&m);
        if(!h&&!m) break;

        /* convert to degree */
        mD=m*6;
        hD=h*5*6+m*0.5;

        degree=fabs(hD-mD);
        if(degree > 180)
            degree = 360 - degree;
        printf("%.3lf\n",degree);
    }

    return 0;
}

2014年7月13日 星期日

uva 315 Network

解法一:

找出所有的 articulation points,把每一個點分別移除,用 DFS 走,確認是否除了被移除的點

外,剩下的所有點都可以走到,

若都可以走到,則此點不是 articulation point。

若有的走不到,則此點不是 articulation point。

注意:儲存的陣列要用 int,char 會不夠大。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int maps[101][101],pass[101]={0};
int places;
int counter;

void DFS(int point){
    int i;

    for(i=1;i<=maps[point][0];i++){
        if(pass[maps[point][i]] != 1){
            ++counter;
            pass[ maps[point][i] ] = 1;
            DFS(maps[point][i]);
        }
    }

    return;
}

int compute_points(int point){
    int i;

    counter=0;
    memset(pass,0,sizeof(pass));
    pass[point]=1;

    for(i=1;i<=places;i++)
        if(i!=point) break;

    pass[i]=1;
    ++counter;
    DFS(i);

    return counter;
}

int main(void){
    int p1,p2,i,points,critical;
    char c;

    while(scanf("%d",&places)!=EOF){
        if(places==0) break;
        memset(maps,0,sizeof(maps));

        while(1){
            scanf("%d",&p1);
            if(p1==0) break;

            c=1;
            while(c!='\n'){
                scanf("%d%c",&p2,&c);

                maps[p1][ ++maps[p1][0] ]=p2;
                maps[p2][ ++maps[p2][0] ]=p1;
            }
        }


        critical=0;
        for(i=1;i<=places;i++){
            if(maps[i][0]==0) continue;
            points=compute_points(i);

            if( points!=(places-1) ) ++critical;
        }

        printf("%d\n",critical);
    }

    return 0;
}

 --------------------------------------------------

解法二  (學習自:http://www.csie.ntnu.edu.tw/~u91029/Component.html#3):

用一次 DFS 找出所有的 articulation point,

需要資訊:1. 此點可以到的最高 ancestor

                    2. 此點是第幾個走到的

判斷 articulation

如果被討論的 point 的其中一個 children,沒有辦法在此 point 被移除後,從被討論的 point 的

ancestor 走到,則此被討論的 point 為 articulation point。

因為為 articulation point 的條件是,此點被移除時,會使剩下的圖變成 disconnected graph,

所以 point 的任一 child 沒有和 point 的 ancestor 有相接時,此 point 為 articulation point。

計算所需的資訊

DFS 時,存入走到此點是第幾個走到的,也是目前可以走到的最高 ancestor (自己),

在走訪自己可以到的 children 時,

如果 child 已被走過,表示此 neighbor 為 ancestor,可以 update 自己可以走到的最高

ancestor。

如果 child 沒有被走過,則往下走。返回時,用此 child 的 "最高可以走到的 ancestor" update

自己可以走到的最高 ancestor,這是為了此點返回時,提供給 parent 的資訊。

然後判斷此點是否為 articuation point,看此 child 最高可以走到的 ancestor 是否是此 point 的

ancestor:

若否,則此點為 articulation point。

特別的判斷情況:root 沒有 parent,所以不能用上面的判斷標準。root 若有兩個以上的

children,則為 articulation point。



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* pass : record the order point traveled */
/* low_back : record the highest ancestor point can reach */
int maps[101][101],pass[101],low_back[101];
int places;
int counter;
int t;

void DFS(int parent,int point){
    int i;
    int child=0,isCritical=0;

    low_back[point]=pass[point]=++t;

    for(i=1;i<=maps[point][0];i++){
        if(maps[point][i] != parent){
            /* point hasn't been traveled => tree edge */
            if(pass[maps[point][i]] == 0){
                child++;

                DFS(point,maps[point][i]);

                /* update ancestor the point can reach */
                if(low_back[point] > low_back[maps[point][i]]){
                    low_back[point]=low_back[maps[point][i]];
                }


                /* if child cannot reach ancestor, */
                /* then the point is critical */
                if(low_back[maps[point][i]] >= pass[point]){
                    isCritical=1;
                }
            }else{
            /* point has been traveled => back edge */
            /* update ancestor the point can reach */
                if(low_back[point] > pass[maps[point][i]]){
                    low_back[point]=pass[maps[point][i]];
                }
            }
        }
    }

    if(parent==point && child <= 1)isCritical=0;

    if(isCritical==1){
        ++counter;
    }

    return;
}

int compute_points(){
    int i;

    t=counter=0;
    memset(pass,0,sizeof(pass));
    memset(low_back,0,sizeof(low_back));

    DFS(1,1);

    return counter;
}

int main(void){
    int p1,p2,i,points,critical;
    char c;

    while(scanf("%d",&places)!=EOF){
        if(places==0) break;
        memset(maps,0,sizeof(maps));

        while(1){
            scanf("%d",&p1);
            if(p1==0) break;

            c=1;
            while(c!='\n'){
                scanf("%d%c",&p2,&c);

                maps[p1][ ++maps[p1][0] ]=p2;
                maps[p2][ ++maps[p2][0] ]=p1;
            }
        }

        critical=compute_points();

        printf("%d\n",critical);
    }

    return 0;
}

uva 488 Triangle Wave

要印出三角形,需要用倆的迴圈跑,一個是控制要印多少行,一的是控制此行要印多少個。

輸出的部分注意最後一筆的最後一個三角形波印完後,不用再多一個換行。


#include <stdio.h>
#include <stdlib.h>

int main(void){
    int cases=0,i,j,m,n;
    int amplitude,frequency;

    scanf("%d",&cases);
    for(i=1;i<=cases;i++){
        scanf("%d%d",&amplitude,&frequency);

        for(j=1;j<=frequency;j++){
            for(m=1;m<=amplitude;m++){
                for(n=1;n<=m;n++){
                    printf("%d",m);
                }
                printf("\n");
            }

            for(m=amplitude-1;m>=1;m--){
                for(n=1;n<=m;n++){
                    printf("%d",m);
                }
                printf("\n");
            }
            if( i==cases && j==frequency )
                break;
            printf("\n");
        }
    }


    return 0;
}

uva 10696 f91

照著題目的意思把遞迴式寫出來即可。

如果要加快速度,可以把算出來的值記錄起來,下次遇到同樣的數字時,就可以不用再遞迴

下去,直接回傳值。



#include <stdio.h>
#include <stdlib.h>

int table[10000000]={0};

int f91(int num){
    if(table[num]!=0){
        return table[num];
    }

    if(num <= 100){
        table[num]=f91(f91(num+11));
        return table[num];
    }else{
        table[num]=num-10;
        return table[num];
    }

    return;
}

int main(void){
    int num;

    while(scanf("%d",&num)==1){
        if(num==0) break;

        printf("f91(%d) = %d\n",num,f91(num));
    }


    return 0;
}

yii2 URL %2F and /

安裝 yii2 時, 

若 --stability 設成 dev,產生的 project 在 URL,/ 會被換成 %2F

--stability 設成 beta,產生的 project 在 URL,/ 可以正常顯示


(安裝過程 from 
 安裝 composer : https://getcomposer.org/doc/00-intro.md#installation-nix
 產生 project : https://github.com/yiisoft/yii2/tree/master/apps/basic    )

step1 安裝 composer.phar:

curl -sS https://getcomposer.org/installer | php
 
step2 產生 project:

當 --stability=dev
php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic 


當 --stability=beta
php composer.phar create-project --prefer-dist --stability=beta yiisoft/yii2-app-basic basic  
 
 
 
 
如果已經安裝了,且 stability 為 dev,可以到 composer.json 做調整:
把 composer.json 裡的 "minimum-stability" : "dev" 改成 "minimum-stability" : "beta"
 

修改完後,執行:php composer.phar update --prefer-dist
它會把 dev-master 相關檔案移除,並安裝 beta 相關檔案




安裝完後,即變成 beta => %2F -> /


原因:

trace code from dev :

安裝完 yii2 後,進入產生的 project,點擊最上面 bar 的 items


進到頁面後,會發現 URL 的 / (slash) 變成 %2F


打開 views/layouts/main.php,發現上面的 bar 是用 Nav 做的


接下來要去找 Nav 的 source code (如果不知道放在哪裡,可以用 locate Nav 找)

打開 vendor/yiisoft/yii2-bootstrap/Nav.php,找到 function renderItem,

最下面 return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, 

$options);

這邊會產生 <a href="..."></a> 的 Html tag



從這邊可以得知,用 yii2 安裝時,提供的 Html 裡的 function a

(可以用 locate Html 找跟 Html 相關的檔案,在一個一個去檢查看是不是)

打開 vendor/yiisoft/yii2/helpers/BaseHtml.php,找 function a,

會呼叫 Url::to($url) 把 URL 產生出來。


接下來要去找 Url 裡面的 function to,

打開 vendor/yiisoft/yii2/helpers/BaseUrl.php,

用 Url 的 toRoute 處理 URL


找到 function toRoute,

用 return Yii::$app->getUrlManager()->createUrl($route); 把產生的網址回傳


打開 vendor/yiisoft/yii2/web/UrlManager.php,

找到 function createUrl,在 else 的部分,$url 在這邊產生好



處理 URL 時,會進到判斷式的 else,

從上圖的 $url = "$baseUrl?{$this->routeParam}=" . urlencode($route);

可以看到 urlencode,會把非大、小寫的英文字母、-_. 以外的字元轉換成 Html code

(可以參考:http://php.net/manual/en/function.urlencode.php)

這裡是 / (slash) 變成 %2F 的原因。


如果把 urlencode 刪掉,/ (slash) 可以正常顯示 (下圖)




trace beta 的 code 後,

打開 vendor/yiisoft/yii2/web/UrlManager.php,

找到 function createUrl,在 else 的部分,


發現 $url = "$baseUrl?{$this->routeParam}=$route";

$route 沒有用 urlencode,所以 URL 的 / (slash) 不會有 %2F。


結論:

版本不同,程式碼不同,所以 dev 版會有 / (slash) 變成 %2F 的問題,而 beta 版不會。


trace code 感想:

當發現有奇怪的東西產生時,一步一步 trace code,找到發生的原因,因為是程式在執行。

2014年7月12日 星期六

uva 108 Maximum Sum

把所有 subrectangles (左上到右下角 )都算出來,以左上角為基準點和 rectangle 裡的任一點

形成的 rectangle,


再一一討論原本 rectangle 裡的所有 subrectangles,利用

算出每一個討論的 rectangle,把最大的找出來。


#include <stdio.h>
#include <stdlib.h>

int main(void){
    int length;
    int i,j,k,m;
    int rectangle[101][101]={0},maximum,tmp;

    while(scanf("%d",&length)!=EOF){
        for(i=1;i<=length;i++){
            for(j=1;j<=length;j++){
                scanf("%d",&rectangle[i][j]);
                rectangle[i][j]+=rectangle[i-1][j]+rectangle[i][j-1]-rectangle[i-1][j-1];
            }
        }

        maximum=0;
        for(i=1;i<=length;i++){
            for(j=1;j<=length;j++){

                for(k=i;k<=length;k++){
                    for(m=j;m<=length;m++){
                        tmp=rectangle[k][m]-rectangle[i-1][m]-rectangle[k][j-1]+rectangle[i-1][j-1];
                        if(tmp>maximum) maximum=tmp;
                    }
                }

            }
        }

        printf("%d\n",maximum);
    }

    return 0;
}

uva 10370 Above Average

算出全部的平均,再看有幾個人在平均以上,最後算出百分比。


#include <stdio.h>
#include <stdlib.h>

int main(void){
    int amount,people,i;
    int score[1001],counter;
    double average,percent;

    scanf("%d",&amount);
    while(amount--){
        scanf("%d",&people);

        average=0;
        for(i=0;i<people;i++){
            scanf("%d",&score[i]);
            average+=score[i];
        }
        average/=people;

        counter=0;
        for(i=0;i<people;i++){
            if(score[i] > average) ++counter;
        }

        percent=((double)counter/people)*100;

        printf("%.3lf%%\n",percent);
    }


    return 0;
}

uva 591 Box of Bricks

題目有說每一 case 都可以重新排成所有 stack 都一樣高度,所以直接平分。

移動時,移動移步會造成另一 stack 少移動一步 (因為移動到其他 stack),所以只要把最後的

高度和所有 stack 現在的高度差加起來除以 2 ,即為最小搬動的次數。

注意:

輸出時,要多一行空行,最後一筆也是。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
    int n,amount,i;
    int bricks[50],mov,sets=0;

    while(scanf("%d",&n)!=EOF){
        if(n==0) break;

        amount=0;
        for(i=0;i<n;i++){
            scanf("%d",&bricks[i]);
            amount+=bricks[i];
        }

        amount/=n;

        mov=0;
        for(i=0;i<n;i++){
            mov+=abs(amount-bricks[i]);
        }
        mov/=2;

        printf("Set #%d\n",++sets);
        printf("The minimum number of moves is %d.\n\n",mov);
    }

    return 0;
}

uva 113 Power of Cryptography

double 讀取,再利用 pow function,把指數變成取根。


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
    double n,p;

    while(scanf("%lf",&n)!=EOF){
        scanf("%lf",&p);

        printf("%.0lf\n",pow(p,1/n));

    }

    return 0;
}