POJ 1703
总时间限制: 1000ms 内存限制: 65536kB
描述
一个城市中有两个犯罪团伙A和B,你需要帮助警察判断任意两起案件是否是同一个犯罪团伙所为,警察所获得的信息是有限的。假设现在有N起案件(N<=100000),编号为1到N,每起案件由团伙A或团伙B所为。你将按时间顺序获得M条信息(M<=100000),这些信息分为两类:
1. D [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息表明它们属于不同的团伙所为
- A [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息需要你回答[a]和[b]是否是同一个团伙所为
注意你获得信息的时间是有先后顺序的,在回答的时候只能根据已经接收到的信息做出判断。
输入
第一行是测试数据的数量T(1<=T<=20)。
每组测试数据的第一行包括两个数N和M,分别表示案件的数量和信息的数量,其后M行表示按时间顺序收到的M条信息。
输出
对于每条需要回答的信息,你需要输出一行答案。如果是同一个团伙所为,回答”In the same gang.”,如果不是,回答”In different gangs.”,如果不确定,回答”Not sure yet.”。
样例输入
1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4
样例输出
Not sure yet.
In different gangs.
In the same gang.
思路:
和“食物链”poj 1182 这道题类似,只是这里的relation只有两种:
relation = 0 : 相同
relation = 1 : 不同
1) 用struct Crime来代表每一个动物, 作为并查集中的元素。凡是知道相互关系的元素都放在一个集合里面
struct Crime{
int parent;
int num;
int relation;
} Crime[100010];
2) 在一个集合中的元素相互关联,如果a,b有关系,b,c有关系,那么a,c之间的关系式可以通过ab、bc的关系推出来的。
node 和 node 的parent (node-parent)有2种关系:
(0) relation = 0: node 和 parent 属于同一个gang
(1) relation = 1: node 和 parent 属于不同的gang
node – parent – root 的关系三者关系的推算:
Node –> root 的 relation = ( Node–> parent+ parent –>root) % 2
3) 压缩: 每一个元素的parent都设置成第一个元素root,并且保存和第一个元素的relation
4) 合并:
x的root是rootA, y的root是rootB,并且知道x与y是属于不同的gang, 现在把b的root设置成a:
已知:x–>rootA, y–>rootB, x–>y:
roots–>roota = (b–>y + y–>x +1)%2
***** 需要注意的几个逻辑点 ******
1. 在初始Crime结点的时候,要把parent设置成自己,并且relation的标记设为SAME
2. 判断not sure: 需要判断的两个结点不在一个集合里面,则不能为not sure
3. 判断的时候(A语句的时候),也要用find(&crime)来把这个节点的parent设置成为root. 因为union()函数并没有把rootb的子结点的parent设置成roota
#include <iostream>
using namespace std;
#define SAME 0
#define DIFF 1
#define NOTSURE 2
struct crime{
int parent; //如果node是root, 即node的parent是自己,储存自己的序号
int num; //node的序号
int relation; // 记录和root/parent的关系
} Crime[100010];
int find(crime* Node){
if (Node->parent==Node->num) return Node->num; // 找到了root
int temp = Node->parent;
Node->parent = find(&Crime[temp]);// 把路径上的每一个点的parent都设置成为了root
Node->relation = (Node->relation + Crime[temp].relation)%2;
// 把路径上的每一个点的relation都设置成为了和root的relation
return Node->parent;
}
void Union(int X, int Y, int ROOTA, int ROOTB){
// 合并的时候不用压缩, 即rootb的所有子结点的parent仍然是rootb 。 后面在判断句子的正误的时候,会先用find函数找root,那时会循环设置parent成为roota
Crime[ROOTB].parent = ROOTA;
Crime[ROOTB].relation =(Crime[Y].relation + Crime[X].relation+1)%2;
}
void Init(int n){
for (int i=0; i<=n; i++){ // 不要忘了循环到n, 而不是n-1
Crime[i].num=i;
Crime[i].parent = i;
Crime[i].relation = SAME;
}
}
int main(){
int T;
cin>>T;
while (T--){
int N,M;
cin>>N>>M;
Init(N);
char AD;
int X,Y;
while(M--){
cin>>AD>>X>>Y;
int rootA = find(&Crime[X]); // 从X到root的路线都“打通了”
int rootB = find(&Crime[Y]); // 从X到root的路线都“打通了”
if (AD == 'D'){
if (rootA != rootB)
Union (X,Y,rootA, rootB);
}
else if (AD=='A'){
if (rootA==rootB && Crime[Y].relation == Crime[X].relation)
cout<<"In the same gang."<<endl;
else if (rootA==rootB && Crime[Y].relation != Crime[X].relation)
cout<<"In different gangs."<<endl;
else if (rootA !=rootB )
cout<<"Not sure yet."<<endl;
}
}
}
return 0;
}