【POJ 1182】食物链【“拓展域”并查集】

题意:

     有三种动物,A吃B,B吃C,C吃A。

     现有K组语句,n个动物,1 x y:x和y是同类,2 x y:x吃y。

     符合下列三个条件之一的即为错误语句,输出错误语句个数。

1.自己吃自己

2.x > n || y > n

3.当前语句和之前的正确语句发生了冲突

思路:

     本题是拓展域并查集的典型题目,利用拆点,将每一个点拆成3个点,分别表示本身,该点的天敌,该点的猎物,然后对于K组语句再一一进行合并和判断,问题就可以迎刃而解。

总结:

     此类真假问题或者一个点有多个状态的问题需要优先考虑是否可以通过并查集得出结果,将一个点进行拓展,巧妙地解决问题。

     但是当情况更加复杂的时候,拓展域并查集就不能再这么好的解决问题,到那个时候我们就需要引出图论中的 2-SAT 解法。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 15*1e4+100;

int fa[N],n,k;

int get(int x)
{
	if(x == fa[x]) return x;
	return fa[x] = get(fa[x]);
}

int main()
{
	scanf("%d%d",&n,&k);
	rep(i,1,3*n) fa[i] = i;
	int cnt = 0;
	rep(i,1,k)
	{
		int x,y,z;
		scanf("%d%d%d",&z,&x,&y);
		int fx1 = get(x), fx2 = get(x+n), fx3 = get(x+2*n);
		int fy1 = get(y), fy2 = get(y+n), fy3 = get(y+2*n);
		if(y > n || x > n){cnt++; continue;}
		if(z == 1)
		{	
			if(fx1 == fy2 || fx1 == fy3 || fx2 == fy1 || fx2 == fy3 || fx3 == fy1 || fx3 == fy2)
			{
				cnt++;
				continue;
			}
			fa[fx1] = fy1, fa[fx2] = fy2, fa[fx3] = fy3;
		}
		else{
			if(y == x || fx1 == fy1 || fx1 == fy3) 
			{
				cnt++;
				continue;
			}
			fa[fx1] = fy2, fa[fx2] = fy3, fa[fx3] = fy1;
		}
	}
	printf("%d\n",cnt);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/82154688
今日推荐