POJ611 The Suspects並查集+優先佇列
阿新 • • 發佈:2018-12-24
題目大意: 非典來襲 n 個人 m 個團隊, n個人的編號為0 --- n-1 其中已知 0 被懷疑攜帶非典病毒,如果一個隊伍中有一個人是
被懷疑攜帶有此病毒,那麼這一個團隊中的所有人都被i懷疑攜帶有非典病毒。
輸入格式:
第一行 n m 代表 n個人 m個團隊
接下來的m行 每一行代表一個團隊 每一行的第一個數為團隊人數 後面接上 此團隊的人員編號
直到輸入中 n m全為0 方才結束。
輸出:所有可能攜帶次病毒的人員的數量。
解析:很明顯 用並查集 另外 考慮一下極端情況
如果輸入的資料為:
30000 1
3 0 29999 15000
0 0
那麼 真是哦存在的只有三個人 0 15000 29999 如果i迴圈從0一個一個列舉 則不太好
好一點的方法就是用優先佇列 將這三個數儲存起來 用的時候 一個一個彈出 即可。
程式碼C:
# include <stdio.h> # define N 30001 void insert(int Tree[],int X);//向堆中插入值 S[WEI] int Delmin(int Tree[]); //刪除堆頭-並返回堆頭 int find(int x); void Link(int x,int y); int tree[N+1]; //堆 int p[N],Q[N]; int main() { int n,m,a,b,c,i,j,k; // freopen("AAA.txt","r",stdin); while(scanf("%d%d",&n,&m)&&(n||m)) { while(m--) { scanf("%d%d",&a,&c); c++; Link(c,c); while(--a>0){ scanf("%d",&b); if(find(++b)!=c)Link(b,c); } } n=0; while(tree[0])Q[n++]=Delmin(tree); for(i=k=0,c=find(1); i<n; i++) if(p[Q[i]]) { if(find(Q[i])==c)tree[++k]=Q[i]; else p[Q[i]]=0; } if(k)printf("%d\n",k); else printf("1\n"); while(k)p[tree[k--]]=0; } return 0; } void insert(int Tree[],int X)//向最小堆中插入X { int par,i=++Tree[0]; //插入X 後 Tree[0]+1 while(i>1) //直到i不是根節點 { par=(i>>1); //父節點為par if(Tree[par]<=X) break; //將<=改為>=即改為最大堆了 Tree[i]=Tree[par]; //否則調整堆 即位置上移 i=par; } Tree[i]=X; //插入新節點 } int Delmin(int Tree[]) { int i=1,L=2,root=Tree[1],X=Tree[Tree[0]--]; while(L<=Tree[0]) { L+=L<Tree[0]&&Tree[L+1]<Tree[L]; if(Tree[L]>=X) break; Tree[i]=Tree[L]; i=L; L=i<<1; } Tree[i]=X; return root; } int find(int x) { int y=x; if(p[x])while(x!=p[x]) x=p[x]; else insert(tree,x); return p[y]=x; } void Link(int x,int y) { p[find(x)]=find(y); }