URL: http://poj.org/problem?id=1703
题目大意:
本题即很经典的“龙帮虎帮”问题。有n个元素(n<=1e5),分布在两个不同的集合里。现在有M个语句(m<=1e5),每个语句共两种:
(1) 给定某两个元素在不同的集合中。
(2) 询问两个元素是否在同一集合中。对于是、否、无法确定的情况,分别输出"In the same gang.", "In different gangs.", "Not sure yet."
思路分析:
假如给定的是两个元素在同一集合中,思路就很明确了。但是现在给定的是两个元素不同集合,而且已知仅有两个集合,于是我们就可以想办法将其转化为两元素同集合问题。
设有元素A,B, 则我们将每个元素分别“克隆”为A', B', 但将她们放入分别与本身不同的另外一个集合中。
同时,保证A和A', B和B', ..., 永远不会同集合。
然后,假如已知A与B不同集合,则需将A和B', B和A'分别放入同一集合(union操作),假如已知A与B同集合,则需把A和B, A'和B'进行union一下即可。
最后,回答询问时,有以下三种情况:
(1) A与B同集合,或A'与B‘同集合:In the same gang.
(2) A与B'同集合,或B与A'同集合:In different gangs.
(3) 其他:Not sure yet.
代码呈现:
(Time:532MS ,Memory:960K ,Code:1005B)
#include<cstdio> using namespace std; const int MAXN = 1e5; int fa[MAXN*2+2]; int n,m; int find_fa(int u) { int i,j,k; i = u; while(fa[i] != i) { i = fa[i]; } fa[u] = i; j = u; while(j != i) { k = fa[j]; fa[j] = i; j = k; } return i; } int main() { int i,t,p,q,pp,qq,x,y; char ch[3]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1; i<=2*n; i++) //Union-Find Sets init { fa[i] = i; } for(i=1; i<=m; i++) //calculate while reading { scanf("%s%d%d",ch,&x,&y); if(ch[0] == 'A') { p = find_fa(x); q = find_fa(y); pp = find_fa(x+n); qq = find_fa(y+n); if(p == q) printf("In the same gang.\n"); else if(pp == q || p == qq) printf("In different gangs.\n"); else printf("Not sure yet.\n"); } else if(ch[0] == 'D') { p = find_fa(x); q = find_fa(y); pp = find_fa(x+n); qq = find_fa(y+n); if(pp != q) fa[pp] = q; if(qq != p) fa[qq] = p; } } } return 0; }
类似题目:
poj 2492 A Bug's Life (几乎一模一样)
poj 1182 && luogu P2024 [NOI 2001]食物链 (一样的思路,元素分成三类)
luogu P1525 [NOIP 2010提高组] 关押罪犯 (个人认为难度较大)