• <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>

            并查集

            Posted on 2009-11-12 22:03 rikisand 閱讀(524) 評論(0)  編輯 收藏 引用 所屬分類: TopcoderAlgorithm

            昨天看了sedgewick的alg in c 的第一章,主要介紹了個find-union 判斷聯通的算法,其實用到了并查集的知識

            剛才偶然看見poj并查集的題集 就copy過來自己也寫寫看~~·

            慢慢來~~ 寫完一道上一道~~

                   POJ 1182 食物鏈
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1182

            還以為是最簡單的一道呢,被列在最前面,原來是擴展的應用,不是那么直接啊~

            糾結了一會兒,看了解題報告才有思路。關鍵是在并查集的基礎上增加一個數組,維護其與根節點的關系;

            詳情寫到注釋里面吧:

            int A[100003][3];
            int root[50005],k[50005];//root記錄節點所屬于的樹木id k記錄節點與根的關系0 同類1子是食物2子是天敵
            int sz[50005];
            int find(int x){
                if(root[x]==x)return x;//如果是根則返回
                 else if(root[root[x]]==root[x])return root[x];//如果第一層,則返回
                int father=root[x];
                root[x]=find(father);//放到第一層,減少下次find時間,減小樹的高度
                k[x]=(k[x]+k[father])%3;//由自己與根的關系以及父節點與根的關系推斷出新的自己與根的關系,實際上是為了解決union后的節點與根的關系
                                                        //因為union后,非根節點并沒有更新k,因此需要在此處處理更新
                return root[x];
            }
            inline void Union(int x,int y,int kind){
                int a=find(x);int b=find(y);
                 if(sz[a]>sz[b]){//判斷后決定,要把size小的放到size大的上去,優化作用不大
                root[b]=a ; //b成為a的子樹
                k[b]=(k[x]-k[y]+kind+3)%3;//要把b變成a的子樹,從a出發,到x,經過kind,到y,再到b ,可以得到kb的狀態改變公式
                sz[a]+=sz[b];}
                else{
                    if(kind==1)kind=2;
                    root[a]=b;
                    k[a]=(k[y]-k[x]+kind+3)%3;
                    sz[b]+=sz[a];
                }
            }
            int main()
            {
                int N,d;
                freopen("d:\\input.txt","r",stdin);
                scanf("%d %d",&N,&d);
                for(int i=1;i<=N;i++)sz[i]=1;
                int cnt=0;
                 for(int s=1;s<=N;s++)root[s]=s;
                int LIE=0;
                int i=0;
                while(i !=d) {
                    scanf("%d %d %d",&A[i][0],&A[i][1],&A[i][2]); 
                    if(A[i][1]>N || A[i][2]>N ) {LIE++;i++;continue;}
                    if(A[i][0]==1){
                        if(find(A[i][1]) == find(A[i][2])){
                            if(k[A[i][1]]!=k[A[i][2]]) LIE++;
                        }
                        else   Union(A[i][1],A[i][2],0); 
                     }
                    else{
                        if( find(A[i][1])==find(A[i][2]) ){if(k[A[i][2]] != ( k[A[i][1]]+1)%3)LIE++;}
                        else  Union(A[i][1],A[i][2],1); 
                    }
                i++;
                }
                cout<<LIE<<endl;
                return 0;
            }
            POJ 1611 The Suspects

            http://acm.pku.edu.cn/JudgeOnline/problem?id=1611


             int G[30005];
             int sz[30005];
             int Find(int x){
                if(G[x]==x)return x;
                else {
                    while(G[x]!=x){//half路徑壓縮~等下試試看全壓縮的效率~那樣就是遞歸調用啦
                        int t=G[x];
                        G[x]=G[t];
                        x=t;
                    }
                    return x;
                }
             }
             void Union(int x,int y){
                if(sz[x]<sz[y])swap(x,y);//把size小的弄到大的上面
                G[y]=x;
                sz[x]+=sz[y];
             }
               int main()
            {
                freopen("d:\\input.txt","r",stdin);
                int N,M,num;
                while(true){
                    scanf("%d %d",&N,&M);
                    if(N==0&&M==0)return 0;
                    for(int i=0;i<N;i++)G[i]=i,sz[i]=1;
                    for(int i=0;i<M;i++){
                        scanf("%d",&num);
                        int root,stu,x,y;
                        for(int j=0;j<num;j++){
                            scanf("%d",&stu);
                            if(j==0)root=Find(stu);//簡單的都和第一個合并
                            else{
                                root=Find(root);
                                x=Find(stu);if(root!=x)Union(root,x);
                            }
                        }
                    }
                    printf("%d\n",sz[Find(0)]);
                }
            }

            POJ 2524 Ubiquitous Religions

            又一道水題~~ 呵呵 

            不貼代碼了 和上面一道基本一樣~
            http://acm.pku.edu.cn/JudgeOnline/problem?id=2524

            POJ 1861

            http://acm.pku.edu.cn/JudgeOnline/problem?id=1861

            kruskal+并查集+half路徑壓縮

            比較基礎的題

            struct Edge{
                int from;
                int to;
                int value;
            }E[15000];
            int A[1005]; 
            int sz[2009];
            bool comp(const Edge& a,const Edge& b){
                return a.value<b.value;
            }
            using namespace std; 
            int Find(int x){
                if(A[x]==x)return x;
                else if(A[A[x]]==A[x]) return A[x];
                int father;
                while(A[x]!=x){
                    father=A[x];
                    A[x]=A[father];//把每一個路過的節點放到祖父下面去
                    x=father;
                }
                return x;
            }
            void Union(int x,int y){
                if(sz[y]>sz[x])swap(x,y);//小的放到大的下面
                sz[x]+=sz[y]; 
                A[y]=x;    
            }
               int main()
            {
                freopen("d:\\input.txt","r",stdin);
                int N,M,num,x,y;
                scanf("%d %d",&N,&M);
                int cnt=0;
                while(cnt<M)  scanf("%d %d %d",&E[cnt].from,&E[cnt].to,&E[cnt].value),cnt++;
                sort(E,E+M,comp);//從小到大選n-1條邊,如果起點和終點在一個集合則continue;else Union
                for(int i=0;i<=N;i++)sz[i]=1,A[i]=i;
                vector<int> ans(N-1);
                int mst=0,MX=0;
                for(int i=0;mst!=N-1;i++){
                    int x=Find(E[i].from);int y=Find(E[i].to);
                    if(x==y)continue;
                    Union(x,y);
                    ans[mst]=i;
                    mst++;
                    if(E[i].value>MX)MX=E[i].value;
                }
                printf("%d\n%d\n",MX,N-1);
                for(int i=0;i<N-1;i++)
                    printf("%d %d\n",E[ans[i]].from,E[ans[i]].to);
            }


                    POJ 1456 Supermarket
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1456
             

                   POJ 1733 Parity game
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1733
             

                   hdu 3038 How Many Answers Are Wrong
            http://acm.hdu.edu.cn/showproblem.php?pid=3038
             

                 POJ 1417 True Liars(難)
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1417
             

               POJ 2912 Rochambeau(難)

            http://acm.pku.edu.cn/JudgeOnline/problem?id=2912

            污污内射久久一区二区欧美日韩| 久久久久亚洲Av无码专| 日本久久久精品中文字幕| 久久精品九九亚洲精品天堂 | 久久精品国产99久久丝袜| 午夜视频久久久久一区| 久久久久亚洲AV无码永不| 国产毛片久久久久久国产毛片| 久久久久久久免费视频| 精品人妻久久久久久888| 久久精品中文字幕无码绿巨人| 国产精品九九久久免费视频 | 久久无码国产| 久久ZYZ资源站无码中文动漫| 久久精品国产72国产精福利| 久久精品人人做人人爽97| 日本久久中文字幕| 久久精品男人影院| 人妻精品久久久久中文字幕69| 欧美亚洲国产精品久久久久| 久久永久免费人妻精品下载| 色老头网站久久网| 久久久久无码精品国产app| 久久国产精品成人免费| 日日躁夜夜躁狠狠久久AV| 亚洲欧洲久久av| 亚洲成av人片不卡无码久久 | 久久久久久久91精品免费观看| 久久线看观看精品香蕉国产| 久久国产精品无码一区二区三区| 狠狠综合久久AV一区二区三区| 一级做a爰片久久毛片毛片| 久久久99精品成人片中文字幕| 中文字幕亚洲综合久久2| 国产欧美一区二区久久| 国产精品久久久久天天影视| 久久精品亚洲精品国产色婷| 99久久免费国产精精品| 久久96国产精品久久久| 久久国产精品久久久| 伊人色综合久久|