Description
求一个图的连通分量
Input
n 顶点数(<=100)
连接的边
Output
连通分量
Sample Input
8
6 3
1 2
2 5
5 4
4 1
8 7
0 0
Sample Output
4
分析
总的来讲,这题我分了5种做法:
1.DFS+邻接矩阵
2.DFS+邻接表
3.BFS+邻接矩阵
4.BFS+邻接表
5.BFS+邻接表+STL
方法一:用一个数组作为邻接矩阵存储,再DFS,要注意判断走过没有。
#include<iostream>
#include<cstdio>
using namespace std;
int n,x,y,a[101][101],p[101],ans,s;//a是矩阵
void dfs(int i)
{
p[i]=1;
for(int j=1;j<=n;j++)
{
if(a[i][j]&&!p[j])//看走过没
{
s++;//分量++
dfs(j);
}
}
}
int main()
{
cin>>n>>x>>y;
while(x!=0&&y!=0)
{
a[x][y]=1;
a[y][x]=1;
cin>>x>>y;
}
for(int i=1;i<=n;i++)
{
if(p[i]==0)
{
s=1;
dfs(i);
ans=max(ans,s);//选择最大的
}
}
cout<<ans;
return 0;
}
方法二:用DFS,但是用链表的方法存,搜索时就省了很多时间,不用一个一个过边。
#include<iostream>
#include<cstdio>
using namespace std;
int n,x,y,p[101],ans,s,k,b[101];
struct node
{
int next,xx;//ss为连接的数,next和同一个点的另一条线
}a[10001];
int dfs(int i)
{
p[i]=1;
for(int j=b[i];j;j=a[j].next))//以now为起点的所有边
{
if(p[a[j].xx]==0)
{
s++;
dfs(a[j].xx);
}
}
return s;
}
int main()
{
cin>>n>>x>>y;
while(x!=0&&y!=0)
{
/*六行等于add(x,y),add(y,x)*/
a[++k].xx=y;//下一个数
a[k].next=b[x];//下一条边
b[x]=k;//替换
a[++k].xx=x;//反过来,做一遍(无向)
a[k].next=b[y];
b[y]=k;
cin>>x>>y;
}
for(int i=1;i<=n;i++)
{
if(p[i]==0)
{
s=1;
dfs(i);
ans=max(ans,s);
}
}
cout<<ans;
return 0;
}
方法三:同样是用邻接矩阵,但用BFS,从每一个位置开始,s记录数量,最后return s再选一个最大值。
#include<iostream>
#include<cstdio>
using namespace std;
int n,x,y,a[101][101],p[101],ans,s;
void bfs(int i)
{
int h=0,t=1,st[101];
st[1]=i;
while(h<t)
{
h++;
for(int j=1;j<=n;j++)
{
if(a[st[h]][j]&&p[j]==0)//是否可到,到过没
{
p[j]=1;
s++;
t++;
st[t]=j;
}
}
}
}
int main()
{
cin>>n>>x>>y;
while(x!=0&&y!=0)
{
a[x][y]=1;
a[y][x]=1;
cin>>x>>y;
}
for(int i=1;i<=n;i++)
{
if(p[i]==0)
{
s=0;
bfs(i);
ans=max(ans,s);
}
}
cout<<ans;
return 0;
}
方法四:用bfs和邻接表,内容基本就是方法二和方法三的合成体,同时注意循环和判断。
#include<iostream>
#include<cstdio>
using namespace std;
int n,x,y,p[101],ans,s,k,b[101];
struct node
{
int next,xx;
}a[10001];
int bfs(int i)
{
int h=0,t=1,st[101];
st[1]=i;
p[i]=1;
while(h<t)
{
h++;
for(int j=b[st[h]];j;j=a[j].next)
{
if(!p[a[j].xx])
{
p[a[j].xx]=1;
s++;t++;
st[t]=a[j].xx;
}
}
}
}
int main()
{
cin>>n>>x>>y;
while(x!=0&&y!=0)
{
a[++k].xx=y;
a[k].next=b[x];
b[x]=k;
a[++k].xx=x;
a[k].next=b[y];
b[y]=k;
cin>>x>>y;
}
for(int i=1;i<=n;i++)
{
if(p[i]==0)
{
s=1;
bfs(i);
ans=max(ans,s);
}
}
cout<<ans;
return 0;
}
方法五:和方法四的思路相同,但运用了一种鲜为人 我知的技术——STL(queue)。把一些跟队列有关的语句用STL实现。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,x,y,p[101],ans,s,k,b[101];
struct node
{
int next,xx;
}a[10001];
int bfs(int i)
{
int h=0,t=1;
queue<int>st;
st.push(i); //入队
while(st.size())
{
int x=st.front();//取队首
st.pop();//出队
for(int j=b[x];j;j=a[j].next)
{
if(!p[a[j].xx])
{
p[a[j].xx]=1;
s++;
st.push(a[j].xx);
}
}
}
}
int main()
{
cin>>n>>x>>y;
while(x!=0&&y!=0)
{
a[++k].xx=y;
a[k].next=b[x];
b[x]=k;
a[++k].xx=x;
a[k].next=b[y];
b[y]=k;
cin>>x>>y;
}
for(int i=1;i<=n;i++)
{
if(p[i]==0)
{
s=0;
bfs(i);
ans=max(ans,s);
}
}
cout<<ans;
return 0;
}
搞掂五种方法啦!开森(/≧▽≦)/