A Bug‘s Life
Description Background Input The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one. Output The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs‘ sexual behavior, or "Suspicious bugs found!" if Professor Hopper‘s assumption is definitely wrong. Sample Input 2 3 3 1 2 2 3 1 3 4 2 1 2 3 4 Sample Output Scenario #1: Suspicious bugs found! Scenario #2: No suspicious bugs found! Hint Huge input,scanf is recommended. |
本题大意:给出若干对飞虫的编号表示这一对飞虫进行交配,让你判断这些交配中是否存在有同性恋的可能。
本题思路:使用带路径压缩的并查集,初始状态下初始化所有昆虫相对于它的父亲结点的性别都为0, 将每对昆虫的交配性别逐一加入并查集,加入并查集时需要先进行判断,如果此时两个昆虫父亲结点的编号相等,则判断两个昆虫相对于父亲的性别是否相等,如果相等则已经找到了同性恋标本,不同则跳过这组数据加入下一组数据。如果两个昆虫的父亲节点的标号不同,则将两个昆虫的父亲归并到同一集合中,假设现在是head[ fy] = fx;即将fy的父亲设置为fx,那么我们在合并时要如何才能维持两个集合相对于父亲结点的性别保持正确呢,我们令x相对于fx的性别代号为value [x],fx相对于fy的性别代号为value[fx],y相对于fy的性别代号为value[y],x相对于y为异性则为1,我们可以知道x相对于fy的性别有两条路可以走,一种是value[x] + value[fx], 另一种是value[y] + 1;显然这两者是相等的,因此我们就可以求出转移状态的函数为value[fx] = (value[y] - value[x] + 1) % 2,那么在find函数中我们肯定也是需要调整x相对于fx的性别的,那么要如何调整呢,我们知道,如果x相对于fx的性别为1,fx相对于fy的性别也是1,那么x相对于fy的性别就是0,也就是说我们可以得知x相对于fy的性别等于(value[x] ^ value[fx])。其实我们也可以用位运算判断转移函数,当且仅当x和y相对于其父节点fx和fy的性别相等时fx相对于fy的性别才与x相对于y的性别相同,这样才会满足我们上面谈到的等式。即满足vlaue[fx] = ~(value[x] ^ value[y])。
下面我们给出两种参考代码:
1 //非位运算 2 #include <cstdio> 3 using namespace std; 4 5 const int maxn = 2010; 6 7 int n, m, flag, tree[maxn], ans[maxn]; 8 9 void Init() { 10 for(int i = 1; i <= n; i ++) { 11 tree[i] = i; 12 ans[i] = 0; 13 } 14 flag = 1; 15 } 16 17 int find(int x) { 18 if(tree[x] != x) { 19 int t = find(tree[x]); 20 ans[x] = (ans[x] + ans[tree[x]]) % 2; 21 return tree[x] = t; 22 } 23 return x; 24 } 25 26 void TUnion(int x, int y) { 27 int fx = find(x), fy = find(y); 28 if(fx == fy) { 29 if(ans[x] == ans[y]) flag = false; 30 } 31 else { 32 tree[fy] = fx; 33 ans[fy] = (ans[x] + 1 - ans[y]) % 2; 34 } 35 } 36 37 int main () { 38 int a, b, t, i, Case; 39 scanf("%d", &t); 40 for(Case = 1; Case <= t; Case ++) { 41 scanf("%d %d", &n, &m); 42 Init(); 43 for(i = 1; i <= m; i ++) { 44 scanf("%d %d", &a, &b); 45 if(flag) 46 TUnion(a, b); 47 } 48 printf("Scenario #%d:\n",Case); 49 if(flag) 50 printf("No suspicious bugs found!\n\n"); 51 else 52 printf("Suspicious bugs found!\n\n"); 53 } 54 return 0; 55 }
位运算代替数学等式:
1 #include <cstdio> 2 using namespace std; 3 4 const int maxn = 2010; 5 6 int n, m, flag, tree[maxn], ans[maxn]; 7 8 void Init() { 9 for(int i = 1; i <= n; i ++) { 10 tree[i] = i; 11 ans[i] = 0; 12 } 13 flag = 1; 14 } 15 16 int find(int x) { 17 if(tree[x] != x) { 18 int t = find(tree[x]); 19 ans[x] = ans[x] ^ ans[tree[x]]; 20 return tree[x] = t; 21 } 22 return x; 23 } 24 25 void TUnion(int x, int y) { 26 int fx = find(x), fy = find(y); 27 if(fx == fy) 28 flag = ans[x] ^ ans[y]; 29 else { 30 tree[fx] = fy; 31 ans[fx] = ~(ans[x] ^ ans[y]); 32 } 33 } 34 35 int main () { 36 int a, b, t, i, Case; 37 scanf("%d", &t); 38 for(Case = 1; Case <= t; Case ++) { 39 scanf("%d %d", &n, &m); 40 Init(); 41 for(i = 1; i <= m; i ++) { 42 scanf("%d %d", &a, &b); 43 if(flag) 44 TUnion(a, b); 45 } 46 printf("Scenario #%d:\n",Case); 47 if(flag) 48 printf("No suspicious bugs found!\n\n"); 49 else 50 printf("Suspicious bugs found!\n\n"); 51 } 52 return 0; 53 }
POJ-2492.A Bug's Life(带权并查集)
原文地址:https://www.cnblogs.com/bianjunting/p/10800985.html