翻译转自该博客:http://blog.youkuaiyun.com/metaphysis/article/details/6848901
问题描述
一场战争在 A 国和 B 国之间开始了。作为一位 C 国的好公民,你决定为你的国家秘密的参加 A 国与 B
国之间的和谈。和谈中还有 n 个人,但你不知道他们分别属于哪个国家。你可以看到他们互相交谈,并能通
过观察双方在一对一交谈时的表现猜测他们是敌人还是朋友。
你的国家需要知道某些特定的两个人之间的关系:到底是属于同一国,还是互相敌对,因此需要你在和谈期间
接收政府传来的问题,并根据你当前的观察做出回答。
正式的来说,考虑一个可以进行如下操作的黑盒:
setFriends(x,y) x 和 y 属于同一国家
setEnemies(x,y) x 和 y 属于不同国家
areFriends(x,y) 仅当你确信 x 和 y 为朋友时返回 true
areEnemies(x,y) 仅当你确信 x 和 y 为敌人时返回 false
若前两种操作与你现有的结论相冲突,你应该报错。“朋友” 关系(符号为 ~)和 “敌对” 关系(符号为 *)
具有如下性质:
~ 是等价关系,即:
1. 若 x ~ y 且 y ~ z,则 x ~ z(朋友的朋友也是朋友)
2. 若 x ~ y,则 y ~ x(朋友是相互的)
3. x ~ x(每个人都是他自己的朋友)
* 满足对称性和反自反性:
1. 若 x * y,则 y * x(敌对是相互的)
2. x * x 总为假(没有人和自己敌对)
3. 若 x * y,且 y * z,则 x ~ z(敌人的敌人是朋友)
4. 若 x ~ y,且 y * z,则 x * z(敌人的朋友是敌人)
操作 setFriends(x,y) 和 setEnemies(x,y) 不能破坏上述性质。
输入
输入每一行包含一个整数 n,表示人数。接下来第一行有三个数,c x y,其中 c 为操作编号。
c = 1,setFriends
c = 2,setEnemies
c = 3,areFriends
c = 4,areEnemies
x 和 y 分别为操作的参数,它们都是区间 [0,n) 内的整数,表示两个不同的人。最后一行为 0 0 0。
输入中所有整数由至少一个空格或换行符隔开。最多可有 10 000 个人,但操作总数没有限制。
输出
对于每个 areFriends 和 areEnemies 操作,输出 “0” (表示假)或者 “1” (表示真)。对于每个
与当前结论冲突的 setFriends 或 setEnemies 操作,你的程序应当输出 “-1”,但该指令不应对后续
操作的执行产生任何影响。成功的 setFriends 或 setEnemies 不产生输出。
输出中的相邻整数间应换行。
解析:
此题可以应用不相交集合数据结构(并查集)来解决。
数组 root 的元素从 [0,N - 1] 存放的是国家 [0,N - 1] 的朋友,元素 [N,2 * N - 1] 存放的是国家 [0,N - 1] 的敌人。
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 10005;
int pa[N*2];
int n;
void init() {
for(int i = 0; i < 2 * n; i++) {
pa[i] = i;
}
}
int find(int x) {
if(x == pa[x])
return x;
else
return pa[x] = find(pa[x]);
}
void solve() {
int c, x, y;
while(scanf("%d%d%d",&c ,&x ,&y) != EOF) {
if(!c && !x && !y) break;
int xf = find(x) , xe = find(x+n);
int yf = find(y) , ye = find(y+n);
if(c == 1) {
if(xf == ye)
printf("-1\n");
else {
pa[xf] = yf;
pa[xe] = ye;
}
}else if(c == 2) {
if(xf == yf)
printf("-1\n");
else {
pa[xf] = ye;
pa[xe] = yf;
}
}else if(c == 3) {
printf("%d\n", xf == yf);
}else if(c == 4) {
printf("%d\n", xf == ye);
}
}
}
int main() {
while(scanf("%d", &n) != EOF) {
init();
solve();
}
return 0;
}