題目:
某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路。
輸入: 測試輸入包含若干測試案例。每個測試案例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。為簡單起見,城鎮從1到N編號。
注意:兩個城市之間可以有多條道路相通,也就是說
3 3
1 2
1 2
2 1
這種輸入也是合法的
當N為0時,輸入結束,該用例不被處理。
輸出: 對每個測試案例,在1行裡輸出最少還需要建設的道路數目。
範例輸入:
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0 範例輸出:
1 0 2 998 提示:
Huge input, scanf is recommended.
AC代碼
/*並查集入門HDU12322017年7月28日19:41:07 */ #include<stdio.h>#include<set>using namespace std;const int maxn=1010;int pre[maxn];int find(int x){int r=x;while(pre[r]!=r)r=pre[r];//尋找到根節點為止 int i=x,j;while(i!=r){j=pre[i];pre[i]=r;i=j;}return r; }void join(int x,int y){int fx=find(x);int fy=find(y);if(fx!=fy) pre[fx]=fy;}int main(){int n,m;while(scanf("%d%d",&n,&m)==2&&n){for(int i=1;i<=n;i++)pre[i]=i;for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);join(a,b);}/*第一種方法,求祖先的數量,把所有節點遍曆一遍如果發現某個點的 祖先 是他自己,那麼這個點一定是祖先節點統計數量,最後結果減一,因為N個連通分量,只需要N-1條路徑就可以將n個連通分量 合并成一個 */ int ans=0;for(int i=1;i<=n;i++){if(find(i)==i) ans++;}printf("%d\n",ans-1);/*這是第二種方法,把每個點的祖先,放到set 裡面,因為集合內建去重,所以裡面的元素個數,即為聯通分量的個數 set<int> ans;for(int i=1;i<=n;i++){int r=find(i);ans.insert(r);}printf("%d\n",ans.size()-1);*/} return 0;}