您的位置:首页 > 其它

uva 12232 Exclusive-OR

2013-08-04 08:53 423 查看
点击打开链接uva 12232

思路: 并查集的扩展应用

分析:

1 题目给定三种指令,I p v表示Xp = v, I p q v表示Xp^Xq = v,

Q k Xp1 Xp2...Xpk求Xp1^Xp2^...^Xpk的值。

2 对于的异或的性质:1 a^0 = a,2 a^c^b^c = a^b,异或一个数偶数次等于没有异或,因为异或偶数次的值为0,根据性质1那么结果没有影响

3 因此对于第一种命令I p v,我们可以虚拟出一个点Xn = 0,那么p^xn = v,那么第一和第二种命令我们可以统一成p^q = v的模式。

4 那么我们设val[i] = Xi^Xfather[i],但是要注意的是Xn要始终为那个集合的跟节点,因为这样我们才能够通过val[i]的值判断Xi是否存在。

5 那么Xp1^Xp2^...^Xpk = (val[Xp1]^val[Xp2]^...^val[Xpk])^(Xfather[xp1]^Xfather[xp2]^...^Xfather[xp2]);因为(val[Xp1]^val[Xp2]^...^val[Xpk])我们很容易求出来,所以我们现在就判断Xfather[xp1]^Xfather[xp2]^...^Xfather[xp2]是否存在,根据性质2我们只需要判断父亲节点出现次数为奇数的,如果父亲节点为Xn,那么值存在,否在不存在我们不能求出ans

代码:

#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 100;
const int MAXN = 20010;

int n , m;
int val[MAXN];
int father[MAXN];

void init(){
for(int i = 0 ; i <= n ; i++){
val[i] = 0;
father[i] = i;
}
}

int find(int x){
if(x != father[x]){
int tmp = father[x];
father[x] = find(father[x]);
val[x] ^= val[tmp];
}
return father[x];
}

bool union_set(int x , int y , int v){
int fx = find(x);
int fy = find(y);
if(fx == fy)
return (val[x]^val[y]) == v;
// 始终使得虚拟的点xn为根节点
if(fx == n)
swap(fx , fy);
father[fx] = fy;
val[fx] = val[x]^v^val[y];
return true;
}

int main(){
char str
;
int p , q , v;
int k , x;
int cas = 1;
while(scanf("%d%d" , &n , &m) && n+m){
init();
printf("Case %d:\n" , cas++);
int facts = 0;
bool isError = false;
while(m--){
scanf("%s" , str);
if(str[0] == 'I'){
gets(str);
facts++;
// 如果是矛盾了,那么直接不用处理即可
if(isError)
continue;
int cnt = sscanf(str , "%d%d%d" , &p , &q , &v);
if(cnt == 2){
v = q;
q = n;
}
if(!union_set(p , q , v)){
isError = true;
printf("The first %d facts are conflicting.\n" , facts++);
}
}
else{
scanf("%d" , &k);
int ans = 0;
bool isKnow = true;
map<int , int>mp;
for(int i = 0 ; i < k ; i++){
scanf("%d" , &x);
if(isError)
continue;
int fx = find(x);
ans ^= val[x];
mp[fx]++;
}
if(isError)
continue;
map<int , int>::iterator it;
for(it = mp.begin() ; it != mp.end() ; it++){
// 如果是奇数判断是否有值,因为偶数个互相异或值为0
if(it->second % 2){
if(it->first != n){
isKnow = false;
break;
}
else
ans ^= val[it->first];
}
}
if(isKnow)
printf("%d\n" , ans);
else
puts("I don't know.");
}
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: