原题:
A war is being lead between two countries, A and B. As a loyal citizen of C, you decide to help your countrys espionage by attending the peace-talks taking place these days (incognito, of course). There are n people at the talks (not including you), but you do not know which person belongs to which country. You can see people talking to each other, and through observing their behaviour during their occasional one-to-one conversations, you can guess if they are friends or enemies. In fact what your country would need to know is whether certain pairs of people are from the same country, or they are enemies. You may receive such questions from Cs government even during the peace-talks, and you have to give replies on the basis of your observations so far. Fortunately nobody talks to you, as nobody pays attention to your humble appearance.
Now, more formally, consider a black box with the following operations:
setFriends(x,y)
setEnemies(x,y)
areFriends(x,y)
areEnemies(x,y)
shows that x and y are from the same country
shows that x and y are from different countries
returns true if you are sure that x and y are friends
returns true if you are sure that x and y are enemies
The first two operations should signal an error if they contradict with your former knowledge. The two relations ‘friends’ (denoted by ∼) and ‘enemies’ (denoted by ∗) have the following properties:
∼ is an equivalence relation, i.e.
1. If x ∼ y and y ∼ z then x ∼ z (The friends of my friends are my friends as well.
2. If x ∼ y then y ∼ x (Friendship is mutual.)
3. x ∼ x (Everyone is a friend of himself.)
∗ is symmetric and irreflexive
1. If x ∗ y then y ∗ x (Hatred is mutual.)
2. Not x ∗ x (Nobody is an enemy of himself.)
Also
1. If x ∗ y and y ∗ z then x ∼ z (A common enemy makes two people friends.
2. If x ∼ y and y ∗ z then x ∗ z (An enemy of a friend is an enemy.
Operations setFriends(x,y) and setEnemies(x,y) must preserve these properties.
Input
The first line contains a single integer, n, the number of people.
Each of the following lines contains a triple of integers, cxy, where c is the code of the operation:
c = 1,
c = 2,
c = 3,
c = 4,
setFriends
setEnemies
areFriends
areEnemies
and x and y are its parameters, which are integers in the range [0, n), identifying two (different) people.
The last line contains ‘0 0 0’.
All integers in the input file are separated by at least one space or line break. The only constraint
is n < 10000, the number of operations is unconstrained.
Output
For every “areFriends” and “areEnemies” operation write ‘0’ (meaning no) or ‘1’ (meaning yes) to the output. Also for every “setFriends” or “setEnemies” operation which contradicts with previous knowledge, output a ‘-1’ to the output; note that such an operation should produce no other effect and execution should continue. A successful “setFriends” or “setEnemies” gives no output. All integers in the output file must be separated by one line break.
Sample Input
10
1 0 1
1 1 2
2 0 5
3 0 2
3 8 9
4 1 5
4 1 2
4 8 9
1 8 9
1 5 2
3 5 2
0 0 0

Sample Output
1
0
1
0
0
-1
0

中文:
有n个人分别输入两个不同的国家,他们再谈判,现在让你通过他们之间的谈话内容判断对方是敌是友。
有4种操作,分别是setFriends(x,y),setEnemies(x,y),areFriends(x,y),areEnemies(x,y),用1到4个数字来标记

如果是set..操作,如果与之前的判断冲突,则输出-1,否则不输出。如果是are操作..如果判断正确输出1否则输出0

#include <bits/stdc++.h>
using namespace std;
const int maxn=10001;
int father[maxn],offset[maxn];
int Find(int x)
{if(x!=father[x]){int tmp=father[x];father[x]=Find(father[x]);offset[x]=(offset[x]+offset[tmp])%2;
//        cout<<"find "<<x<<" "<<tmp<<" "<<offset[x]<<endl;}return father[x];
}
int Union(int x,int y,int d)
{int fx=Find(x);int fy=Find(y);if(fx==fy){
//        cout<<"union "<<offset[x]<<" "<<offset[y]<<endl;if((offset[x]-offset[y]+2)%2!=d)return -1;elsereturn 1;}father[fy]=fx;offset[fy]=(offset[x]-offset[y]+d+2)%2;//   cout<<"union "<<offset[x]<<" "<<offset[y]<<endl;return 0;
}
void init(int n)
{for(int i=0;i<=n;i++)father[i]=i;memset(offset,0,sizeof(offset));
}
int main()
{ios::sync_with_stdio(false);int n;while(cin>>n){int x,y,d;init(n);while(cin>>d>>x>>y,x+y+d){if(d<=2){d--;if(Union(x,y,d)==-1){cout<<-1<<endl;}}else{d-=3;father[y]=Find(y);
//                cout<<"......."<<endl;father[x]=Find(x);
//                cout<<"offset "<<offset[x]<<" "<<offset[y]<<endl;
//                cout<<"father "<<father[x]<<" "<<father[y]<<endl;if(father[x]==father[y]&&(offset[x]-offset[y]+2)%2==d)cout<<1<<endl;elsecout<<0<<endl;}}//break;}return 0;
}

思路:
非常经典的并查集加向量偏移,第一次做这类题的时候是poj上的食物链,我记得我刚学并查集的时候遇到这题,由于当时对递归理解的不好,这题简直把我恶心坏了。没想到能在uva上再次遇到它,真是怀念。
向量偏移就是在并查集的路径压缩过程也就是子节点与父节点之间变换时,维持关系变换使得给出的节点关系能够通过其父节点之间的关系得到分类的操作。
现在设置偏移量offset[]用来记录当前节点与父节点的偏移量(因为并查集当中每个节点都只有一个父节点)
以此题为例,只需设置两种关系,朋友与敌人。
现在设置偏移量offset[x]=0时表示x与父节点的关系是朋友,offset[x]=1时表示x与父节点的关系是敌人。

那么,如图所示的原始关系,可以转换成如下关系(两方敌对那么两个节点之间的值是1,否则是0,箭头方向表示父节点方向)


转化后

敌人的敌人变成朋友,所以1和3是一伙的

那么在Find()过程,也就是查找根节点的过程当中,通过路径压缩判断当前节点与父节点至今的关系。
公式为 offset[x]=(offset[x]+offset[father[x]])%2 x节点与新的父节点之间的偏移量等于,之前x与父节点的偏移量加上父节点与爷爷节点之间偏移量的和,模2的目的是因只有两种状态,也就是朋友和敌人,如果不用模运算,就得用if判断,更麻烦。

在合并的过程当中,也就是设置两个节点之间关系的过程。
首先找到两个节点的x,y的父节点fx,fy。如果fx和fy相等,说明x和y之前连接过,已经有关系了,那么就判断当前要设置的关系是否和之前的关系冲突。判断冲突的方法是判断x与y对它们相同根节点的偏移量是否相同,如果x和y都认为根节点是敌人或是朋友,那么x和y肯定是同伙,否则它们就是敌人,使用公式
(offset[x]-offset[y]+2)%2!=d d是x与y要设置的关系,只有0和1两种,0是朋友,1是敌人。 公式结果为真,说明与之前的冲突。

如果要设置的两个节点x和y的父节点不相同,说明x和y之间还没有建立关系,也就是不知道是朋友还是敌人。
那么,通过给定的关系d,把x与y建立关系。

首先,把y的父节点fy连接到fx上面,表示x和y之前,以及与x,y向量的所有数据连接在一起。
然后,计算新连接的节点对父节点的偏移值(之前fx作为fy的父节点,那么就要计算fy与fx的偏移值)

怎么计算偏移值? 已经有了x与fx之间的偏移值,y与fy之间的偏移值,x与y之间的偏移值(就是要设置x与y之间的关系值d),现在要求fx与fy之间的值。,利用向量的知识。

改变箭头指向,只需要用种类数减去offset值即可,这里的种类数为2(敌人和朋友)
(如果fy与y相等,那么offset[y]=0)

最后通过上面的计算就可以得到种类结果了,种类数同样可以推广到3个

挑战程序设计竞赛还有另外一种方法,书上有详述

给出一组数据,自己手动模拟一遍

5
2 0 1
2 1 2
2 2 3
3 0 2
3 1 2
0 0 0

uva 10158 War相关推荐

  1. uva 10158 War (并查集)

    uva 10158 War 四个操作:1)使AB成为朋友.2)使AB成为敌人.3)询问AB是不是朋友.4)询问AB是不是敌人.PS:敌人的敌人是朋友.朋友的朋友是朋友. 开一个2 * n的数组,0~n ...

  2. uva 10158 - War(并查集)

    题目链接:10158 - War 题目大意:有n个人,若干个命令,每个人分属于不同的国家,并且代表国家与其他代表会谈,这将决定国与国之间的同盟关系,1:a与b结盟  2:a与b决裂(成为敌人) 3:判 ...

  3. Uva 10158 War

    并查集的应用 直接阔成2倍.后N项为对应的敌人 #include <map> #include <set> #include <list> #include < ...

  4. UVA - 10158 War

    题意:看了题解的解释:点击打开链接,知道了就是并查集的操作,用i+n表示i的敌人 #include <iostream> #include <cstdio> #include ...

  5. UVA 10158 War 并查集

    第一次自己写并差集一次ac,纪念一下 #include<iostream> #include<algorithm> #include<cstdio> #includ ...

  6. uva 10158(并查集)

    题意:若干个人中告诉你1 a b是朋友2 a b是敌人3 a b查询是否是朋友3 a b查询是否是敌人.前两个若是矛盾则输出-1,否则不输出.后面两个是输出1不是输出0.并且朋友的朋友是朋友,敌人的敌 ...

  7. Uva(10158)

    这题真的是并查集的经典题目= = 题意是给出n个人,然后给出若干的操作 1表示让a,b成为朋友,若与前面的朋友敌人关系相矛盾,输出-1 2表示让a,b成为敌人,若与前面的朋友敌人关系矛盾输出-1 3判 ...

  8. UVA 10158 (记忆化搜索)

    题目大意: 已知有n个人,他们之间有敌对还有友好关系,已知: 自己和自己为好友. a和b为好友,那么b和a也为好友 自己的敌人是敌人. 自己和自己不能为敌人. a和b为敌人,那么b和a也为敌人 敌人的 ...

  9. π-Algorithmist分类题目(3)

    原题网站:Algorithmist,http://www.algorithmist.com/index.php/Main_Page π-Algorithmist分类题目(3) Probability ...

最新文章

  1. java 线程池 分组_JAVA面试题解惑系列(十)——话说多线程
  2. 给计算机图片文件夹加密码,电脑文件夹设置密码的方法是什么【图文】
  3. time and value
  4. Local Binary Convolutional Neural Networks ---卷积深度网络移植到嵌入式设备上?
  5. 第十二届蓝桥杯C++赛后感
  6. Unity上的Oculus Quset2开发(2) —— 在VR里打棒球
  7. 常用的php.ini 配置选项
  8. ExtJs页面布局总结(转载)
  9. OTcl与C++,NS2是如何识别并调用执行协议的 转自百思论坛
  10. sql-查询不同状态下的数据之和
  11. C#编码应注意的事项
  12. mysql的数据备份及恢复
  13. 室内设计——住宅空间室内设计(包含预览图jpg和.psd文件)
  14. 视频编码格式——h264优点
  15. 无法安装visual studio code,snap vscode has install-snap change in process
  16. 【电子知识摘要】合金电阻
  17. 炫酷的后台管理系统UI界面
  18. voc旋转标注数据转dota类型
  19. PL/SQL 工具远程连接Oracle数据库方法,plsql免安装oracle客户端直接配置oci实战演示
  20. linux下查看显卡和驱动版本

热门文章

  1. 什么牌子的蓝牙耳机耐用?2023年最值得入手的蓝牙耳机分享
  2. 【图像处理】关于颜色的万花筒(RGB--HSV)
  3. 渗透中超全的Google hack语法
  4. Envoy架构理解--理解xDS/Listener/Cluster/Router/Filter
  5. Oracle管理的文件(OMF)的具体含义
  6. python(蟒蛇)三大控制流程语句
  7. Python小知识:推导式用法大全,Comprehension
  8. 职业规划-Android工程师
  9. 解决:U盘无法安装到这个磁盘选中的磁盘具有MBR分区表
  10. vue实现动态css,巧用 CSS 动画实现动态气泡背景__Vue.js__CSS__前端