前一段时间学了简单的并查集,网上逛技术博客,看到并查集的拓展,在原有并查集的基础上,加入集合内部元素和其父节点之间的关系,这样的拓展,可以解决更多问题
题目链接:
http://poj.org/problem?id=2492
题目大意:
输入n个bug,bug之间有interaction,当前假设异性之间才interaction,但是需要验证,给定这些interaction对,判定是否满足假设
如果男<->女和女<->男,满足条件,如果存在男<->男或者女<->女,则假设不满足
方法:
采用并查集拓展,加入relations[]数组,其中relations[x]表示x和父节点关系,relations[x] = 0表示x和父节点关系为同性,relations[x] = 1表示x和父节点关系为异性
代码如下:
#include <cstdio> #include <cstring> #include <cstdlib> using namespace std; #define MAX 5005 int parent[MAX]; //记录父节点 int relations[MAX]; //relations[x]记录x和父节点之间的关系 //其中relations[x] = 0表示x和父节点关系为同性, relations[x] = 1表示x和父节点关系为异性 //集合查找 int findSet(int x) { int temp = parent[x]; if(temp == x) return x; parent[x] = findSet(temp); relations[x] = (relations[x] + relations[temp]) % 2; //根据老的父节点和新父节点关系,修改relations[x]值 return parent[x]; } //合并集合 void unionSet(int root1, int root2) { int x = findSet(root1); int y = findSet(root2); if(x == y) return ; parent[x] = y; relations[x] = ((relations[root1] - relations[root2] + 1) % 2); return ; } //初始化数据 void init(void) { memset(relations, 0, sizeof(relations)); for(int i = 0; i < MAX; i++) parent[i] = i; return ; } int main() { int temp1, temp2; int n, m; int num; int count = 1; scanf("%d", &num); while(num--) { scanf("%d%d", &n, &m); init(); int flag = 1; for(int i = 0; i < m; i++) { scanf("%d%d", &temp1, &temp2); if(findSet(temp1) == findSet(temp2)) { if(relations[temp1] != (relations[temp2] + 1) % 2) //如果不满足异性关系,有矛盾 flag = 0; } else { unionSet(temp1, temp2); } } if(flag) { printf("Scenario #%d:\nNo suspicious bugs found!\n\n", count++); } else { printf("Scenario #%d:\nSuspicious bugs found!\n\n", count++); } } return 0; }