問題鏈接:HDU1232 暢通工程
Problem Description 某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路?
Input 測試輸入包含若干測試用例。每個測試用例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。爲簡單起見,城鎮從1到N編號。
Output 對每個測試用例,在1行裏輸出最少還需要建設的道路數目。
Sample Input 4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
Sample Output 1 0 2 998 Hint Hint Huge input, scanf is recommended.
|
問題分析:這是一個有關圖的連通性問題,可以用並查集來解決。並查集中,連通的各個結點都會指向相同的根。
構建一個並查集,使得相互連通的子圖指向相同的根,發現到兩個互不相連的子圖時,增加一條邊使之相連。
以下兩種方法均正確,第二種更爲簡潔
#include <iostream>
#include <cstring>
using namespace std;
//////////////ac 並查集
int p[1005];
int find(int x)
{
if(p[x]==x)
{
return x;
}
else{
int y=find(p[x]);
p[x]=y;
return y;
}
}
int main()
{
int n,m;
int a,b;
memset(p,0,sizeof(p));
while(cin>>n>>m&&n!=0)
{
for(int i=1;i<=n;i++)
{
p[i]=i;
}
//輸入邊構造並查集
for(int i=0;i<m;i++)
{
cin>>a>>b;
int x=find(a);
int y=find(b);
if(x!=y)
{
p[x]=y;
}
}
// 逐個結點檢查是否聯通,如果不聯通則修一條道路使其聯通
int s=0;
int t=find(1);
for(int i=2;i<=n;i++)
{
if(find(i)!=t)
{
int x=find(find(i));
int y=find(t);
if(x!=y)
{
p[x]=y;
}
s++;
}
}
cout<<s<<endl;
}
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
//////////////ac 並查集
int p[1005];
int find(int x)
{
if(p[x]==x)
{
return x;
}
else{
int y=find(p[x]);
p[x]=y;
return y;
}
}
int main()
{
int n,m;
int a,b;
int cnt;
memset(p,0,sizeof(p));
while(cin>>n>>m&&n!=0)
{
for(int i=1;i<=n;i++)
{
p[i]=i;
cnt=n-1;//使所有節點連通需要的邊的數目
}
//輸入邊構造並查集
for(int i=0;i<m;i++)
{
cin>>a>>b;
int x=find(a);
int y=find(b);
if(x!=y)
{
p[x]=y;
cnt--;//每往並查集里加一個節點,所需邊的個數減1
}
}
cout<<cnt<<endl;
}
return 0;
}