標籤:檔案 os 資料 for io 代碼
聯通塊是指給定n個點,輸入a,b(1<=a,b<=n),然後將a,b串連,凡是串連在一起的所有數就是一個聯通塊;
題意:第一行輸入n,m,分別表示有n個數,有輸入m對連接點,以下將要輸入m行(輸入資料到檔案截止);
輸出:第一行要求輸出聯通塊的個數,並在第二行分別輸出每個聯通塊中點的數量,每個數之間以一個空格隔開。
範例 1
5 3
1 4
2 5
3 5
輸出:2
2 3
樣列2
9 8
1 2
2 3
3 4
3 7
4 5
4 6
7 8
7 9
輸出:
1
9
如果不明白的話可以畫圖試試,最多花半個小時,要是早這樣不知道能省下多少個半小時呢;
此題可以利用並查集求解:
首先可以將N個點看成獨立的聯通塊,然後每個每個獨立的聯通塊都有一個節點,然後每次串連兩個點,就將它們的節點加在一起;
代碼如下:
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1010;
int p[maxn];//作為每個獨立的點
int sum[maxn];//每個節點下面串連的點
int find(int x)
{
if(x==p[x])return x;
return p[x]=find(p[x]);//壓縮路徑
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0)//如果沒有資料那就直接按照格式輸出零 ,一般不會有這種輸入
{
cout<<0<<endl<<0<<endl;
continue;
}
for(int i=1;i<=n;i++)//初始化,令每一個點成為獨立的聯通塊
{
p[i]=i;
sum[i]=1;//每個聯通塊中節點的個數為 1
}
int a,b;
for(int i=1;i<=m;i++)
{
cin>>a>>b;
int fa=find(a);//尋找a的前端節點
int fb=find(b);//尋找b的前端節點
if(fa!=fb)//如果前端節點不同
{
p[fa]=fb;//將兩個點合并
sum[fb]+=sum[fa];//並且使新前端節點中的個數加上新串連的聯通塊所含節點的個數
}
}
int count=0;
for(int i=1;i<=n;i++)
{
if(p[i]==i)//計算聯通塊的數量
{
count++;
}
}
cout<<count<<endl;
int flag=0;
for(int i=1;i<=n;i++)
{
if(p[i]==i)
{
if(flag==1)cout<<" ";
flag=1;
cout<<sum[i];
}
}
cout<<endl;
}
return 0;
}
這個題目利用DFS求解也可以。
要建立一個二維資料,將要連接點的點連在一起,並且用一個一位元據記錄每個點是否被搜尋過;
代碼如下:
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1000;
int map[maxn][maxn];
int vis[maxn];
int tot;
int n,m;
void dfs(int s)
{
tot++;
vis[s]=1;
for(int i=1;i<=n;i++)
if(!vis[i]&&map[s][i])//當從1到n都搜尋一遍後 變會自動停止
{
dfs(i);
}
}
int main()
{
int now=0;
int v,u;
while(cin>>n>>m)
{
tot=0;
now=0;
int sum[maxn];
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=1;
}
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
tot=0;
dfs(i);
sum[++now]=tot;
}
}
cout<<now<<endl;
for(int i=1;i<=now;i++)
{
if(i>1)cout<<" ";
cout<<sum[i];
}
cout<<endl;
}
return 0;
}
利用BFS做也是比較方便的;
利用隊棧儲存每次搜尋到的資料,並且在處理完成它的子節點後刪除;同時利用一個數組記錄是否拜訪過它;
#include <cstdio>
#include <cstring>
#include<iostream>
#include <queue>
using namespace std;
#define N 100
int n,m;
int map[N][N];
int mk[N];
int sum[N];
int total;
void bfs(int s)
{
queue <int> Q;
Q.push(s);
mk[s]=1;
while(!Q.empty())
{
int u=Q.front();Q.pop();
total++;
for(int i=1;i<=n;i++)
{
if(map[u][i]&&!mk[i])
{
mk[i]=1;
Q.push(i);
}
}
}
}
int main()
{
int u,v;
int now=0;
while(scanf("%d%d",&n,&m)==2)
{
now=0;
memset(map,0,sizeof(map));
memset(mk,0,sizeof(mk));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=1;
}
for(int i=1;i<=n;i++)
{if(mk[i]==0)
{
total=0;
bfs(i);
sum[++now]=total;
}
}
cout<<now<<endl;
for(int i=1;i<=now;i++)
{
if(i>1)cout<<" ";
cout<<sum[i];
}
cout<<endl;
}
return 0;
}
以上三個方法,都是比較容易理解上手的,能夠很好的提高做類似題目的能力;