POJ 1182 解题报告

这道题似乎是union-find的经典题目。

这道题我在捕食关系上面弄得很乱,(改改说不定能弄对),最后看了discuss上面一个同学的解法写的,最后和这个同学的代码就一模一样了:http://poj.org/showmessage?message_id=344806

大致理解为:对任意一个编号为i的动物,它能捕食的动物集合和N+i都是一个集合的, 捕食它的动物集合和2N+i是一个集合的。这样总的集合大小为3N,编号为0~3N-1。好处是理解比较清晰。

判断两个动物(X, Y)可不可能是同一个类型的,只需要比较下Y和X捕食的动物或捕食X的动物在不在一个集合里面就可以了。如果可能是一个类型的,那就是真话,把X,Y放到一个集合里面,同时, X+N和Y+N,以及X+2N和Y+2N也要并起来。

判断两个动物(X,Y)是不是X能够捕食Y,也比较清晰。即看Y是不是和X或者捕食X的动物在一个集合里面。如果不能的话,那么X是可能会捕食Y的。这样,把X和捕食Y的放在一个集合里面。同理,把捕食X的和Y捕食的并起来,把X捕食的和Y并起来。

1182Accepted1796K297MSG++2178B

/* 
ID: thestor1 
LANG: C++ 
TASK: poj1182 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

int findset(int X, std::vector<int> &parent)
{
	if (parent[X] != X)  
	{  
		parent[X] = findset(parent[X], parent);
	}  
	return parent[X];
}

void unionset(int X, int Y, std::vector<int> &parent, std::vector<int> &rank)
{
	int rx = findset(X, parent);
	int ry = findset(Y, parent);
	if (rx == ry)
	{
		return;
	}
	if (rank[rx] < rank[ry])
	{
		parent[rx] = ry;
	}
	else if (rank[ry] < rank[rx])
	{
		parent[ry] = rx;
	}
	else
	{
		parent[rx] = ry;
		rank[ry]++;
	}
}

int main()
{
	// std::ios::sync_with_stdio(false);
	int N, K;
	// cin >> N >> K;
	scanf("%d%d", &N, &K);
	
	std::vector<int> parent(3 * N);
	std::vector<int> rank(3 * N);
	for (int i = 0; i < 3 * N; ++i)
	{
		parent[i] = i;
		rank[i] = 0;
	}

	int nlies = 0;
	for (int i = 0; i < K; ++i)
	{
		int D, X, Y;
		// cin >> D >> X >> Y;
		scanf("%d%d%d", &D, &X, &Y);
		
		if (X < 1 || Y < 1 || X > N || Y > N)
		{
			nlies++;
			continue;
		}

		if (X == Y)
		{
			if (D == 2)
			{
				nlies++;
			}
			continue;
		}

		X--, Y--;

		// int rx = findset(X, parent);
		int ry = findset(Y, parent);
		// X and Y are the same group
		if (D == 1)
		{	
			if (findset(X + N, parent) == ry || findset(X + 2 * N, parent) == ry)
			{
				nlies++;
			}
			else
			{
				unionset(X, Y, parent, rank);
				unionset(X + N, Y + N, parent, rank);
				unionset(X + 2 * N, Y + 2 * N, parent, rank);
			}
		}
		else
		{
			// X eats Y
			assert (D == 2);
			if (findset(X, parent) == ry || findset(X + 2 * N, parent) == ry)
			{
				nlies++;
			}
			else
			{
				unionset(X, Y + 2 * N, parent, rank);
				unionset(X + N, Y, parent, rank);
				unionset(X + 2 * N, Y + N, parent, rank);
			}
		}
	}

	// cout << nlies << endl;
	printf("%d\n", nlies);
	return 0;  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值