原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4496
参看资料:https://blog.csdn.net/u013480600/article/details/18278857
题目大意:
开始时给定一个连接好的图,按连接时的边的顺序,再将每条边拆去,问每拆去一条边剩余多少连通块?
【看不明白就原题链接】
解题思路:
图论处当然有查找连通块的方法,如果按正向思维,先输入五条边,再输入四条边,再。。,不如直接倒序输入,将每一次输入之前都做判断,看此时有多少连通块,最后将每一次求得的结果再倒序输出,即为正确答案。
代码实现:
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=10000+5;
const int maxm=100000+5;
//并查集fa
int fa[maxn];
int findset(int x)
{
return fa[x]==-1? x : fa[x]=findset(fa[x]);
}
int bind(int u,int v)
{
int fu=findset(u);
int fv=findset(v);
if(fu!=fv)
{
fa[fu]=fv;
return 1;//连通分量少了1个
}
return 0;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
memset(fa,-1,sizeof(fa));
//vc按序保存所有的边
vector<pair<int,int> > vc;
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vc.push_back(make_pair(x,y));
}
//保存连通分量数
vector<int> res;
int cnt=n;//当前连通分量数
res.push_back(cnt);
for(int i=m-1;i>=1;i--)//逆序依次连接所有边
{
cnt -= bind(vc[i].first,vc[i].second);
res.push_back(cnt);
}
for(int i=res.size()-1;i>=0;i--)
printf("%d\n",res[i]);
}
return 0;
}
测试代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
const int maxn=10000+5;
const int maxm=100000+5;
//并查集fa
int fa[maxn];
int findset(int x)
{
cout<<" 进入findset("<<x<<")\n 数组fa[";
for(int i=0;i<20;i++){
cout<<fa[i]<<" ";
}cout<<"]"<<endl;
return fa[x]==-1? x : fa[x]=findset(fa[x]);
}
int bind(int u,int v)
{
cout<<" 进入bind("<<u<<","<<v<<")"<<endl;
int fu=findset(u);
int fv=findset(v);
cout<<" fu="<<fu<<" fv="<<fv<<endl;
if(fu!=fv)
{
cout<<" 两点不是一个块上的"<<endl;
fa[fu]=fv;
cout<<" 数组fa[";
for(int i=0;i<20;i++){
cout<<fa[i]<<" ";
}cout<<"]"<<endl;
return 1;//连通分量少了1个
}
return 0;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
cout<<"\nn="<<n<<" m="<<m<<endl;
memset(fa,-1,sizeof(fa));
cout<<"数组fa[";
for(int i=0;i<20;i++){
cout<<fa[i]<<" ";
}cout<<"]"<<endl;
//vc按序保存所有的边
vector<pair<int,int> > vc;
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vc.push_back(make_pair(x,y));
}
for(int i=0;i<m;i++)
{
cout<<"vc["<<i<<"]=("<<vc[i].first<<","<<vc[i].second<<")"<<endl;
}
//保存连通分量数
vector<int> res;
int cnt=n;//当前连通分量数
cout<<"cnt="<<cnt<<endl;
res.push_back(cnt);
for(int i=m-1;i>=1;i--)//逆序依次连接所有边
{
cout<<" i="<<i<<endl;
cout<<" bind("<<vc[i].first<<","<<vc[i].second<<")"<<endl;
cnt -= bind(vc[i].first,vc[i].second);
res.push_back(cnt);
cout<<" cnt="<<cnt<<endl;
cout<<"数组res[";
for(int i=0;i<sizeof(res);i++){
cout<<res[i]<<" ";
}cout<<"]"<<endl;
}
for(int i=res.size()-1;i>=0;i--)
printf("%d\n",res[i]);
}
return 0;
}