并查集的简单例题(基础)
HDU - 1213
题意:每次给两个人,找出最后的帮派数(帮派之间没有共同的一个人,否则将是一个帮派了)
思路:①最简单的并查集应用,直接套用模板。
②利用DFS进行搜索也可以。
代码:
并查集:
#include<iostream>
#include<cstdlib>
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int p[M],v[M];
int is(int a)
{
int g=a,h=a;
while(g!=p[g])
{
g=p[g];
}
while(h!=g)//状态压缩,否则最后的遍历可能要超时。
{
int k=p[h];
p[h]=g;
h=k;
}
return g;
}
int main()
{
int tt,i,j,m,n,x,y,ans;
cin>>tt;
while(tt--)
{
ans=0;
me(v,0);
cin>>n>>m;
for(i=1;i<=n;i++)
{
p[i]=i;
}
for(i=0;i<m;i++)
{
cin>>x>>y;
int l=is(x),r=is(y);
if(l!=r)
{
if(l>r)swap(l,r);
p[r]=l;
}
}
for(i=1;i<=n;i++)
{
v[is(i)]=1;
}
for(i=1;i<=n;i++)
{
if(v[i]!=0)ans++;
}
cout<<ans<<endl;
}
//system("pause");
return 0;
}
DFS做法:(我本来也不知道可以这样做,后来看网上可以这样写)
#include<iostream>
#include<cstdlib>
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int ans,n;
int v[M],q[1100][1100];
void dfs(int u)
{
int i;
v[u]=1;
for(i=1;i<=n;i++)
{
if(!v[i])
{
if(q[i][u])
{
dfs(i);
}
}
}
}
int main()
{
int tt,i,j,m,x,y;
cin>>tt;
while(tt--)
{
ans=0;
me(q,0);
me(v,0);
cin>>n>>m;
for(i=1;i<=m;i++)
{
cin>>x>>y;
q[x][y]=1;
q[y][x]=1;
}
for(i=1;i<=n;i++)
{
//从0~n查找v[i]等于0的人,等于0说明他还没有所属帮派,所以帮派加1
if(!v[i])
{
dfs(i);
ans++;
}
}
cout<<ans<<endl;
}
//system("pause");
return 0;
}
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
POJ - 2524
题意:与上题一样,求帮派数。
思路:并查集,代码与上题基本一样。
代码:
#include<iostream>
#include<cstdlib>
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int v[M],p[M];
int is(int root)
{
int g=root;
while(p[g]!=g)
g=p[g];
while(root!=g)
{
int k=p[root];
p[root]=g;
root=k;
}
return g;
}
void Qi(int l,int r)
{
int s=is(l);
int s1=is(r);
if(s1==s)return ;
p[s]=s1;
}
int main()
{
int i,x,y,n,tt=0;
LL m;
while(cin>>n>>m)
{
if(!n&&!m)break;
int ans=0;
me(v,0);
for(i=1;i<=n;i++)
{
p[i]=i;
}
for(i=1;i<=m;i++)
{
cin>>x>>y;
if(x<y)swap(x,y);//这里我取比较小的,也可以不选,结果一样。
Qi(x,y);
}
for(i=1;i<=n;i++)
{
v[is(i)]=1;
}
for(i=1;i<=n;i++)
{
if(v[i])ans++;
}
printf("Case %d: %d\n",++tt,ans);
}
//system("pause");
return 0;
}
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
POJ - 1611
题意:给出几个帮派,帮派之间可能有相互认识的人,所以这两个(多个)帮派有可以合并。找到与0号在一个帮派的所以人(包括0号)。
思路:在输入每个帮派时,将其中某一个定为老大(我习惯与把最小号定为老大)在把老大能连接的帮派给连上,在让这个输入的帮派其他人的父节点等于这个老大。
代码:
#include<iostream>
#include<cstdlib>
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int p[M],a[M];
int is(int root)
{
if(root==p[root])
return p[root];
else return p[root]=is(p[root]);
}
int main()
{
int n,m,i,j,k,minn;
while(cin>>n>>m)
{
if(!n&&!m)break;
for(i=0;i<n;i++)
p[i]=i;
int ans=0;
for(i=0;i<m;i++)
{
cin>>k;
minn=inf;
for(j=1;j<=k;j++)
{
scanf("%d",&a[j]);
minn=min(a[j],minn);
}
p[is(minn)]=minn;
p[minn]=minn;
for(j=1;j<=k;j++)
{
if(a[j]!=minn)
{
p[is(a[j])]=minn;
}
}
}
int x=is(0);
for(i=1;i<n;i++)
{
if(is(i)==x)ans++;
}
cout<<ans+1<<endl;
}
//system("pause");
return 0;
}