• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            A Za, A Za, Fighting...

            堅信:勤能補拙

            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1936

            思路:
            第一個思路是搜索,然后直接寫代碼:
             1 void
             2 search(int depth, int start_from)
             3 {
             4     int i;
             5     char ch;
             6     char *ptr, *rt;
             7     if(depth == sub_len) {
             8         mark = 1;
             9         return;
            10     }
            11     ch = sub[depth];
            12     ptr = seq;
            13     while(!mark && ((rt=strchr(ptr+start_from, ch))!=NULL)) {
            14         search(depth+1, rt-seq+1);
            15         ptr = rt+1;
            16     }
            17 }
            結果上述代碼RE,想著即使不RE,估計也得TLE

            看了別人代碼,發現原來可以這么簡單:
             1 #include<stdio.h>
             2 #include<stdlib.h>
             3 #include<string.h>
             4 #define MAX_LEN 100001
             5 char sub[MAX_LEN], seq[MAX_LEN];
             6 int sub_len, seq_len;
             7 
             8 int
             9 main(int argc, char **argv)
            10 {
            11     char *sub_p, *seq_p;
            12     while(scanf("%s %s", sub, seq) != EOF) {
            13         sub_len = strlen(sub);
            14         seq_len = strlen(seq);
            15         for(sub_p=sub, seq_p=seq; sub_p<sub+sub_len && seq_p<seq+seq_len; )
            16             if(*sub_p == *seq_p) {
            17                 ++sub_p;
            18                 ++seq_p;
            19             } else
            20                 ++seq_p;
            21         if(sub_p == sub+sub_len)
            22             printf("Yes\n");
            23         else
            24             printf("No\n");
            25     }
            26 }

            posted @ 2010-08-10 21:00 simplyzhao 閱讀(120) | 評論 (0)編輯 收藏
            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1020

            思路:
            原本以為是挺簡單的題,結果卻始終不知道怎么搜索,艾...備受打擊
            雖然目前對于回溯部分的代碼理解起來已經沒有困難,對于每次搜索都從占用最少的列開始,還是不明白為什么...

            參考:
            http://www.shnenglu.com/RyanWang/archive/2008/10/26/65051.aspx

            代碼:
             1 #define MAX_LEN 42
             2 #define MAX_SIZE 11
             3 int size, n;
             4 int used[MAX_LEN], pieces[MAX_SIZE];
             5 int flag;
             6 
             7 void
             8 dfs(int depth)
             9 {
            10     int i, j, col, min_used=MAX_LEN;
            11     if(depth == n) {
            12         flag = 1;
            13         return;
            14     }
            15     for(i=1; i<=size; i++)
            16         if(used[i] < min_used) {
            17             min_used = used[i];
            18             col = i;
            19         }
            20     for(i=10; i>=1; i--) {
            21         if(pieces[i]>0 && used[col]+i<=size && col+i-1<=size) {
            22             for(j=col; j<=col+i-1; j++)
            23                 if(used[j]>min_used)
            24                     break;
            25             if(j>col+i-1) {
            26                 --pieces[i];
            27                 for(j=col; j<=col+i-1; j++)
            28                     used[j] += i;
            29                 dfs(depth+1);
            30                 for(j=col; j<=col+i-1; j++)
            31                     used[j] -= i;
            32                 ++pieces[i];
            33             }
            34         }
            35     }
            36 }
            37 
            38 int
            39 main(int argc, char **argv)
            40 {
            41     int i, tmp, tests, sum;
            42     scanf("%d"&tests);
            43     while(tests--) {
            44         memset(used, 0sizeof(used));
            45         memset(pieces, 0sizeof(pieces));
            46         flag = 0;
            47         scanf("%d %d"&size, &n);
            48         sum = 0;
            49         for(i=0; i<n; i++) {
            50             scanf("%d"&tmp);
            51             ++pieces[tmp];
            52             sum += (tmp*tmp);
            53         }
            54         if(sum == size*size)
            55             dfs(0);
            56         printf("%s\n", flag==1 ? "KHOOOOB!" : "HUTUTU!");
            57     }
            58 }
            posted @ 2010-08-10 19:42 simplyzhao 閱讀(236) | 評論 (0)編輯 收藏
            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1988

            思路:
            并查集的妙用
            up[i]記錄節點i到根節點的距離(有多少元素)
            sum[i]記錄以i作為根節點的樹所包含的節點的個數
            重點是在進行union與find操作時如何更新這兩個數組,find操作所暗含路徑壓縮時up數組的更新較難理解

            參考:
            http://www.shnenglu.com/longzxr/archive/2009/07/13/89974.html

            代碼:
             1 #include<stdio.h>
             2 #include<stdlib.h>
             3 #include<string.h>
             4 #define MAX_NUM 30005
             5 int father[MAX_NUM], up[MAX_NUM], sum[MAX_NUM];
             6 
             7 void
             8 init()
             9 {
            10     int i;
            11     for(i=1; i<MAX_NUM; i++) {
            12         father[i] = i;
            13         sum[i] = 1;
            14         up[i] = 0;
            15     }
            16 }
            17 
            18 int
            19 find(int item)
            20 {
            21     int tmp = father[item];
            22     if(father[item] != item) {
            23         father[item] = find(father[item]);
            24         up[item] += up[tmp];
            25     }
            26     return father[item];
            27 }
            28 
            29 void
            30 uunion(int top, int down)
            31 {
            32     int a = find(top);
            33     int b = find(down);
            34     if(a == b)
            35         return;
            36     father[b] = a;
            37     up[b] = sum[a];
            38     sum[a] += sum[b];
            39 }
            40 
            41 int
            42 main(int argc, char **argv)
            43 {
            44     int p, top, down, r, cube;
            45     char ch[2];
            46     scanf("%d"&p);
            47     init();
            48     while(p--) {
            49         scanf("%s", ch);
            50         if(ch[0== 'M') {
            51             scanf("%d %d"&top, &down);
            52             uunion(top, down);
            53         } else {
            54             scanf("%d"&cube);
            55             r = find(cube);
            56             printf("%d\n", sum[r]-up[cube]-1);
            57         }
            58     }
            59 }
            posted @ 2010-08-09 14:59 simplyzhao 閱讀(217) | 評論 (0)編輯 收藏
            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=2524

            思路:
            簡單并查集,求連通分支的個數,一次AC

            代碼:
             1 #include<stdio.h>
             2 #include<stdlib.h>
             3 #include<string.h>
             4 #define MAX_NUM 50001
             5 int father[MAX_NUM];
             6 int rank[MAX_NUM];
             7 int total;
             8 
             9 void
            10 init(int n)
            11 {
            12     int i;
            13     for(i=1; i<=n; i++)
            14         father[i] = i;
            15     memset(rank, 0sizeof(rank));
            16     total = n;
            17 }
            18 
            19 int 
            20 find(int item)
            21 {
            22     if(father[item] != item)
            23         father[item] = find(father[item]);
            24     return father[item];
            25 }
            26 
            27 void
            28 uunion(int item1, int item2)
            29 {
            30     int a = find(item1);
            31     int b = find(item2);
            32     if(a == b)
            33         return;
            34     --total;
            35     if(rank[a] > rank[b])
            36         father[b] = a;
            37     else {
            38         father[a] = b;
            39         if(rank[a] == rank[b])
            40             ++rank[b];
            41     }
            42 }
            43 
            44 int
            45 main(int argc, char **argv)
            46 {
            47     int n, m, i, j, k, cnt=0;
            48     while(scanf("%d %d"&n, &m)!=EOF) {
            49         if(n==0 && m==0)
            50             break;
            51         init(n);
            52         for(k=0; k<m; k++) {
            53             scanf("%d %d"&i, &j);
            54             uunion(i, j);
            55         }
            56         printf("Case %d: %d\n"++cnt, total);
            57     }
            58 }
            posted @ 2010-08-09 09:11 simplyzhao 閱讀(142) | 評論 (0)編輯 收藏
            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1611

            思路:
            話說是最基礎的并查集,每個分支的根節點賦予該分支節點個數的相反數,妙...

            代碼:
             1 #include<stdio.h>
             2 #include<stdlib.h>
             3 #include<string.h>
             4 #define MAX_LEN 30001
             5 int parent[MAX_LEN];
             6 
             7 void
             8 init(int size)
             9 {
            10     int i;
            11     for(i=0; i<size; i++)
            12         parent[i] = -1;
            13 }
            14 
            15 int
            16 find(int item)
            17 {
            18     int tmp, root = item;
            19     while(parent[root] >= 0)
            20         root = parent[root];
            21     while(item != root) {
            22         tmp = parent[item];
            23         parent[item] = root;
            24         item = tmp;
            25     }
            26     return root;
            27 }
            28 
            29 void
            30 uunion(int item1, int item2)
            31 {
            32     int root1 = find(item1);
            33     int root2 = find(item2);
            34     if(root1 != root2) {
            35         if(parent[root1] < parent[root2]) { /* tree with 'root1' has more nodes */
            36             parent[root1] += parent[root2];
            37             parent[root2] = root1;
            38         } else {
            39             parent[root2] += parent[root1];
            40             parent[root1] = root2;
            41         }
            42     }
            43 }
            44 
            45 int
            46 main(int argc, char **argv)
            47 {
            48     int n, m, gp, i, j, r, stu;
            49     while(scanf("%d %d"&n, &m)!=EOF) {
            50         if(n==0 && m==0)
            51             break;
            52         init(n);
            53         for(i=0; i<m; i++) {
            54             scanf("%d"&gp);
            55             for(j=0; j<gp; j++) {
            56                 scanf("%d"&stu);
            57                 if(j==0)
            58                     r = stu;
            59                 else
            60                     uunion(r, stu);
            61             }
            62         }
            63         printf("%d\n"-parent[find(0)]);
            64     }
            65 }
            posted @ 2010-08-07 21:51 simplyzhao 閱讀(126) | 評論 (0)編輯 收藏
                      出處: http://hi.baidu.com/fandywang_jlu/blog/item/b49e40893ddbb0b00f244485.html

                   并查集:(union-find sets)是一種簡單的用途廣泛的集合. 并查集是若干個不相交集合,能夠實現較快的合并和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數、最小公共祖先、帶限制的作業排序,還有最完美的應用:實現Kruskar算法求最小生成樹。其實,這一部分《算法導論》講的很精煉。

                   一般采取樹形結構來存儲并查集,在合并操作時可以利用樹的節點數(加權規則)或者利用一個rank數組來存儲集合的深度下界--啟發式函數,在查找操作時進行路徑壓縮使后續的查找操作加速。這樣優化實現的并查集,空間復雜度為O(N),建立一個集合的時間復雜度為O(1),N次合并M查找的時間復雜度為O(M Alpha(N)),這里Alpha是Ackerman函數的某個反函數,在很大的范圍內這個函數的值可以看成是不大于4的,所以并查集的操作可以看作是線性的。
            它支持以下三種操作:
              -Union (Root1, Root2) //合并操作;把子集合Root2和子集合Root1合并.要求:Root1和 Root2互不相交,否則不執行操作.
              -Find (x) //搜索操作;搜索元素x所在的集合,并返回該集合的名字--根節點.
              -UFSets (s) //構造函數。將并查集中s個元素初始化為s個只有一個單元素的子集合.
              -對于并查集來說,每個集合用一棵樹表示。
              -集合中每個元素的元素名分別存放在樹的結點中,此外,樹的每一個結點還有一個指向其雙親結點的指針。   
                   -為簡化討論,忽略實際的集合名,僅用表示集合的樹的根來標識集合。

            以下給出我的兩種實現:

            //Abstract: UFSet                 

            //Author:Lifeng Wang Fandywang

            // Model One Model 2 路徑壓縮方式不同,合并標準不同

            const int MAXSIZE = 500010;

            int rank[MAXSIZE];    // 節點高度的上界

            int parent[MAXSIZE]; // 根節點

            int FindSet(int x){// 查找+遞歸的路徑壓縮

                if( x != parent[x] ) parent[x] = FindSet(parent[x]);

                 return parent[x];

            }

            void Union(int root1, int root2){

                 int x = FindSet(root1), y = FindSet(root2);

                 if( x == y ) return ;

                 if( rank[x] > rank[y] ) parent[y] = x;

                 else{

                     parent[x] = y;

                     if( rank[x] == rank[y] ) ++rank[y];

                 }

            }

            void Initi(void){

                 memset(rank, 0, sizeof(rank));

                 forint i=0; i < MAXSIZE; ++i ) parent[i] = i;

            }

            // Model Two

            const int MAXSIZE = 30001;

            int pre[MAXSIZE]; //根節點i,pre[i] = -num,其中num是該樹的節點數目;

                               //非根節點j,pre[j] = k,其中kj的父節點

            int Find(int x){//查找+非遞歸的路徑壓縮

                 int p = x;

                 while( pre[p] > 0 )    p = pre[p];

                 while( x != p ){

                     int temp = pre[x]; pre[x] = p; x = temp;

                 }

                 return x;

            }

            void Union(int r1, int r2){

                 int a = Find(r1); int b = Find(r2);

                 if( a == b ) return ;

                 //加權規則合并

                 if( pre[a] < pre[b] ){

                     pre[a] += pre[b]; pre[b] = a;

                 }

                 else {

                     pre[b] += pre[a]; pre[a] = b;

                 }

            }

            void Initi(void)

            {

                for( int i=0; i < N; ++i ) pre[i] = -1;

            }          

            并查集的一些題目和我的相關解題報告:

            POJ 1611 The Suspects          最基礎的并查集 
            POJ 2524 Ubiquitous Religions 最基本的并查集
            POJ 1182 食物鏈       并查集的拓展
            注意: 只有一組數據;
            要充分利用題意所給條件:有三類動物A,B,C,這三類動物的食物鏈
            構成了有趣的環形。A吃B, B吃C,C吃A。也就是說:只有三個group
            POJ 2492 A Bug's Life 并查集的拓展
            法一:深度優先遍歷
            每次遍歷記錄下該點是男還是女,只有:男-〉女,女-〉男滿足,否則,找到同性戀,結束程序。
            法二:二分圖匹配
            法三:并查集的拓展:和1182很像,只不過這里就有兩組,而1182是三組,1611無限制
            POJ 1861 Network == zju_1542    并查集+自定義排序+貪心求"最小生成樹"
            答案不唯一,不過在ZOJ上用QSORT()和SORT()都能過,在POJ上只有SORT()才能過...
            POJ 1703 Find them, Catch them 并查集的拓展
            這個和
            POJ 2492 A Bug's Life很像,就是把代碼稍微修改了一下就AC了!
            注意:And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. 就是說只有兩個組。
            POJ 2236 Wireless Network        并查集的應用
            需要注意的地方:1、并查集;2、N的范圍,可以等于1001;3、從N+1行開始,第一個輸入的可以是字符串。
            POJ 1988 Cube Stacking            并查集很好的應用
            1、與 銀河英雄傳說==NOI2002 Galaxy一樣;2、增加了一個數組behind[x],記錄戰艦x在列中的相對位置;3、詳細解題報告見銀河英雄傳說。

            JOJ 1905 Freckles   == POJ 2560 最小生成樹

            法一:Prim算法;法二:并查集實現Kruskar算法求最小生成樹

            JOJ 1966 Super Market III == PKU 1456 Supermarket 帶限制的作業排序問題(貪心+并查集)

            提高題目:
            POJ 2912 Rochambeau
            POJ 1733 Parity game    
            POJ 1308 Is It A Tree?

            posted @ 2010-08-07 20:28 simplyzhao 閱讀(83) | 評論 (0)編輯 收藏
                            出處: http://webotu.com/Article.asp?id=102

                來看一個實例,杭電1232暢通工程 http://acm.hdu.edu.cn/showproblem.php?pid=1232
                首先在地圖上給你若干個城鎮,這些城鎮都可以看作點,然后告訴你哪些對城鎮之間是有道路直接相連的。最后要解決的是整幅圖的連通性問題。比如隨意給你兩個點,讓你判斷它們是否連通,或者問你整幅圖一共有幾個連通分支,也就是被分成了幾個互相獨立的塊。像暢通工程這題,問還需要修幾條路,實質就是求有幾個連通分支。如果是1個連通分支,說明整幅圖上的點都連起來了,不用再修路了;如果是2個連通分支,則只要再修1條路,從兩個分支中各選一個點,把它們連起來,那么所有的點都是連起來的了;如果是3個連通分支,則只要再修兩條路……
            以下面這組數據輸入數據來說明
            4 2
            1 3
            4 3
                第一行告訴你,一共有4個點,2條路。下面兩行告訴你,1、3之間有條路,4、3之間有條路。那么整幅圖就被分成了1-3-4和2兩部分。只要再加一條路,把2和其他任意一個點連起來,暢通工程就實現了,那么這個這組數據的輸出結果就是1。好了,現在編程實現這個功能吧,城鎮有幾百個,路有不知道多少條,而且可能有回路。
                這可如何是好?我以前也不會呀,自從用了并查集之后,嗨,效果還真好!我們全家都用它!
                并查集由一個整數型的數組和兩個函數構成。數組pre[]記錄了每個點的前導點是什么,函數find是查找,join是合并。
            int pre[1000 ];

            int find(int x)
            {
            //查找根節點
            int r=x;
            while (pre[r ]!=r)
            r=pre[r ];
            //路徑壓縮
            int i=x;
            int j;
            while(i!=r)
            {
            j=pre[i ];
            pre[i ]=r;
            i=j;
            }
            //返回根節點
            return r;
            }
            void join(int x,int y)
            {
            //判斷x y是否連通
            //如果已經連通,就不用管了
            //如果不連通,就把它們所在的連通分支合并起來
                int fx=find(x),fy=find(y);
            if(fx!=fy)
            pre[fx ]=fy;
            }
                為了解釋并查集的原理,我將舉一個更有愛的例子。
                話說江湖上散落著各式各樣的大俠,有上千個之多。他們沒有什么正當職業,整天背著劍在外面走來走去,碰到和自己不是一路人的,就免不了要打一架。但大俠們有一個優點就是講義氣,絕對不打自己的朋友。而且他們信奉“朋友的朋友就是我的朋友”,只要是能通過朋友關系串聯起來的,不管拐了多少個彎,都認為是自己人。這樣一來,江湖上就形成了一個一個的群落,通過兩兩之間的朋友關系串聯起來。而不在同一個群落的人,無論如何都無法通過朋友關系連起來,于是就可以放心往死了打。但是兩個原本互不相識的人,如何判斷是否屬于一個朋友圈呢?我們可以在每個朋友圈內推舉出一個比較有名望的人,作為該圈子的代表人物,這樣,每個圈子就可以這樣命名“齊達內朋友之隊”“羅納爾多朋友之隊”……兩人只要互相對一下自己的隊長是不是同一個人,就可以確定敵友關系了。
                但是還有問題啊,大俠們只知道自己直接的朋友是誰,很多人壓根就不認識隊長,要判斷自己的隊長是誰,只能漫無目的的通過朋友的朋友關系問下去:“你是不是隊長?你是不是隊長?”這樣一來,隊長面子上掛不住了,而且效率太低,還有可能陷入無限循環中。于是隊長下令,重新組隊。隊內所有人實行分等級制度,形成樹狀結構,我隊長就是根節點,下面分別是二級隊員、三級隊員。每個人只要記住自己的上級是誰就行了。遇到判斷敵友的時候,只要一層層向上問,直到最高層,就可以在短時間內確定隊長是誰了。由于我們關心的只是兩個人之間是否連通,至于他們是如何連通的,以及每個圈子內部的結構是怎樣的,甚至隊長是誰,并不重要。所以我們可以放任隊長隨意重新組隊,只要不搞錯敵友關系就好了。于是,門派產生了。
            按此在新窗口瀏覽圖片
                下面我們來看并查集的實現。
                int pre[1000];
                這個數組,記錄了每個大俠的上級是誰。大俠們從1或者0開始編號(依據題意而定),pre[15]=3就表示15號大俠的上級是3號大俠。如果一個人的上級就是他自己,那說明他就是掌門人了,查找到此為止。也有孤家寡人自成一派的,比如歐陽鋒,那么他的上級就是他自己。每個人都只認自己的上級。比如胡青牛同學只知道自己的上級是楊左使。張無忌是誰?不認識!要想知道自己的掌門是誰,只能一級級查上去。
                find這個函數就是找掌門用的,意義再清楚不過了(路徑壓縮算法先不論,后面再說)。
            int find(int x)
            {
            //查找根節點
            int r=x;
            while (pre[r ]!=r)//如果我的上級不是掌門
            r=pre[r ];//我就接著找他的上級,直到找到掌門為止。
            //返回根節點
            return r;//掌門駕到~~~
            }
                再來看看join函數,就是在兩個點之間連一條線,這樣一來,原先它們所在的兩個板塊的所有點就都可以互通了。這在圖上很好辦,畫條線就行了。但我們現在是用并查集來描述武林中的狀況的,一共只有一個pre[]數組,該如何實現呢?
                還是舉江湖的例子,假設現在武林中的形勢如圖所示。虛竹小和尚與周芷若MM是我非常喜歡的兩個人物,他們的終極boss分別是玄慈方丈和滅絕師太,那明顯就是兩個陣營了。我不希望他們互相打架,就對他倆說:“你們兩位拉拉勾,做好朋友吧。”他們看在我的面子上,同意了。這一同意可非同小可,整個少林和峨眉派的人就不能打架了。這么重大的變化,可如何實現呀,要改動多少地方?其實非常簡單,我對玄慈方丈說:“大師,麻煩你把你的上級改為滅絕師太吧。這樣一來,兩派原先的所有人員的終極boss都是師太,那還打個球啊!反正我們關心的只是連通性,門派內部的結構不要緊的。”玄慈一聽肯定火大了:“我靠,憑什么是我變成她手下呀,怎么不反過來?我抗議!”抗議無效,上天安排的,最大。反正誰加入誰效果是一樣的,我就隨手指定了一個。這段函數的意思很明白了吧?
            void join(int x,int y)//我想讓虛竹和周芷若做朋友
            {
                int fx=find(x),fy=find(y); //虛竹的老大是玄慈,芷若MM的老大是滅絕
                if(fx!=fy) //玄慈和滅絕顯然不是同一個人
                      pre[fx ]=fy; //方丈只好委委屈屈地當了師太的手下啦
            }
                再來看看路徑壓縮算法。建立門派的過程是用join函數兩個人兩個人地連接起來的,誰當誰的手下完全隨機。最后的樹狀結構會變成什么胎唇樣,我也完全無法預計,一字長蛇陣也有可能。這樣查找的效率就會比較低下。最理想的情況就是所有人的直接上級都是掌門,一共就兩級結構,只要找一次就找到掌門了。哪怕不能完全做到,也最好盡量接近。這樣就產生了路徑壓縮算法。
                設想這樣一個場景:兩個互不相識的大俠碰面了,想知道能不能揍。
                于是趕緊打電話問自己的上級:“你是不是掌門?”
                上級說:“我不是呀,我的上級是誰誰誰,你問問他看看。”
                一路問下去,原來兩人的最終boss都是東廠曹公公。
            “哎呀呀,原來是記己人,西禮西禮,在下三營六組白面葫蘆娃!”
            “幸會幸會,在下九營十八組仙子狗尾巴花!”
                兩人高高興興地手拉手喝酒去了。
                “等等等等,兩位同學請留步,還有事情沒完成呢!”我叫住他倆。
                “哦,對了,還要做路徑壓縮。”兩人醒悟。
                白面葫蘆娃打電話給他的上級六組長:“組長啊,我查過了,其習偶們的掌門是曹公公。不如偶們一起及接拜在曹公公手下吧,省得級別太低,以后查找掌門麻環。”
                “唔,有道理。”
                白面葫蘆娃接著打電話給剛才拜訪過的三營長……仙子狗尾巴花也做了同樣的事情。
                這樣,查詢中所有涉及到的人物都聚集在曹公公的直接領導下。每次查詢都做了優化處理,所以整個門派樹的層數都會維持在比較低的水平上。路徑壓縮的代碼,看得懂很好,看不懂也沒關系,直接抄上用就行了。總之它所實現的功能就是這么個意思。
            按此在新窗口瀏覽圖片
                回到開頭提出的問題,我的代碼如下:
            #include

            int pre[1000 ];

            int find(int x)
            {
            int r=x;
            while (pre[r ]!=r)
            r=pre[r ];
            int i=x;
            int j;
            while(i!=r)
            {
            j=pre[i ];
            pre[i ]=r;
            i=j;
            }
            return r;
            }
            int main()
            {
            int n,m,p1,p2,i,total,f1,f2;
            while(scanf("%d",&n) && n)//讀入n,如果n為0,結束
            {
            //剛開始的時候,有n個城鎮,一條路都沒有
            //那么要修n-1條路才能把它們連起來
            total=n-1;
            //每個點互相獨立,自成一個集合,從1編號到n
            //所以每個點的上級都是自己
            for(i=1;i<=n;i++)
            {
            pre[i ]=i;
            }
            //共有m條路
            scanf("%d",&m);
            while(m--)
            {
            //下面這段代碼,其實就是join函數,只是稍作改動以適應題目要求
            //每讀入一條路,看它的端點p1,p2是否已經在一個連通分支里了
            scanf("%d %d",&p1,&p2);
            f1=find(p1);
            f2=find(p2);
            //如果是不連通的,那么把這兩個分支連起來
            //分支的總數就減少了1,還需建的路也就減了1
            if(f1!=f2)
            {
            pre[f2 ]=f1;
            total--;
            }
            //如果兩點已經連通了,那么這條路只是在圖上增加了一個環
            //對連通性沒有任何影響,無視掉
            }
            //最后輸出還要修的路條數
            printf("%d\n",total);
            }
            return 0;
            }
            posted @ 2010-08-07 19:55 simplyzhao 閱讀(190) | 評論 (0)編輯 收藏
                 摘要:                                               A*算法解題參考:http://www.shnenglu.com/lo...  閱讀全文
            posted @ 2010-08-07 16:10 simplyzhao 閱讀(151) | 評論 (0)編輯 收藏
                 摘要: 英文原版: http://www.gamedev.net/reference/articles/article2003.asp中文翻譯版: http://www.shnenglu.com/christanxw/archive/2006/04/07/5126.html中文翻譯版轉載如下(非常感謝原作者以及翻譯作者):概述雖然掌握了 A* 算法的人認為它容易,但是...  閱讀全文
            posted @ 2010-08-07 10:46 simplyzhao 閱讀(470) | 評論 (0)編輯 收藏
                 摘要: 問題:http://acm.pku.edu.cn/JudgeOnline/problem?id=1077思路:傳說中經典的經典解法有: 單向BFS,雙向BFS,還有A*等啟發式搜索算法今天先寫了前兩種方法的代碼,至于啟發式算法待續判重: 全排列的哈希,詳見: http://www.shnenglu.com/Joe/archive/2010/08/06/122410.html代碼(單向BFS...  閱讀全文
            posted @ 2010-08-06 16:36 simplyzhao 閱讀(201) | 評論 (0)編輯 收藏
            僅列出標題
            共21頁: First 12 13 14 15 16 17 18 19 20 Last 

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            国产精品一区二区久久国产| 久久婷婷五月综合97色直播| 久久国产精品免费一区二区三区| 久久精品国产精品亜洲毛片| 亚洲婷婷国产精品电影人久久| 欧洲人妻丰满av无码久久不卡| 国产精品成人无码久久久久久| 亚洲伊人久久大香线蕉综合图片| 99精品久久久久久久婷婷| 综合久久国产九一剧情麻豆 | 久久精品国产一区二区三区日韩| 91精品国产9l久久久久| 一本大道久久东京热无码AV| 久久天堂AV综合合色蜜桃网| 狠狠人妻久久久久久综合蜜桃| 亚洲国产美女精品久久久久∴| 一个色综合久久| 三级片免费观看久久| 久久国产一片免费观看| 亚洲AV无码一区东京热久久| 欧美久久久久久精选9999| 久久超乳爆乳中文字幕| 久久综合亚洲色HEZYO社区| 欧美成a人片免费看久久| 国产精品青草久久久久婷婷| 亚洲国产精品成人久久| 伊人久久大香线蕉综合热线| 久久影院久久香蕉国产线看观看| 国产精自产拍久久久久久蜜| 久久久久久狠狠丁香| 精品久久久久久久无码| 亚洲色大成网站www久久九| 久久笫一福利免费导航| 亚洲第一永久AV网站久久精品男人的天堂AV | 久久99国产精品二区不卡| 久久久久久夜精品精品免费啦| 亚洲精品乱码久久久久久蜜桃图片| 一级做a爰片久久毛片看看| 亚洲国产精品成人AV无码久久综合影院| 久久99精品久久久久久不卡| 国产精品欧美久久久久无广告 |