POJ 2912 Rochambeau 【枚举+带权并查集】

POJ 2912 Rochambeau

题目链接:vjudge传送门

题目大意:
给定n个孩子,编号[0,n),以及m组两人剪刀石头布的结果,n个人中有一个孩子是裁判,剩余的人被分成3组,通一组人出同一个手势,裁判也参与见到石头布游戏,只不过有它的那组结果是随机给的(即正确与否不保证),问能否判断出哪个孩子是裁判,若可以求出最少需要前多少条语句可以判断出。

具体思路:
带权并查集,权值数组的维护与poj1182食物链这一题是一样的,没做过的可以先去看一下,这是题解
关于枚举操作:
依次假设每个孩子为裁判,然后通过m组关系判断该孩子是否为裁判(有作为裁判的孩子参与的忽略),若不是则记录在第几条语句发生冲突。
经过N轮枚举,能得出总共有cnt个孩子可以当裁判

  • cnt=0,说明 Impossible
  • X>1,说明Can not determine
  • X==1时,输出那个作为裁判孩子的编号,且输出其他所有小孩中发生冲突语句的 最大值max,即通过前max条语句我们就能知道N-1个小孩都不可能是裁判

参考:https://blog.csdn.net/u013480600/article/details/21198751

具体代码:

#include 
#include
using namespace std;
const int N = 505,M=2005;
int fa[N], ral[N];
int isNotJudge[N], sentence[N];	//是否是裁判,以及不是裁判是发生矛盾的语句是第几条
struct Node {
     
	int u, v, r;
	void setNode(int u, int v, char op) {
     
		this->u = u, this->v = v;
		if (op == '>')r = 1;
		else if (op == '<')r = 2;
		else r = 0;
	}
}round[M];
void init(int n)
{
     
	for (int i = 0; i < n; i++)
	{
     
		fa[i] = i;
		ral[i] = 0;
	}
}
int find(int son)
{
     
	if (son == fa[son])
		return son;
	int root = fa[son];
	fa[son] = find(fa[son]);
	ral[son] = (ral[son] + ral[root]) % 3;
	return fa[son];
}
void Unite(int x, int y, int d)
{
     
	int fx = find(x);
	int fy = find(y);
	fa[fy] = fx;
	ral[fy] = (3 - ral[y] + d  + ral[x]) % 3;
}
int main()
{
     
	int n,m;
	while (~scanf("%d%d", &n, &m))
	{
     
		for (int i = 0; i < m; i++)
		{
     
			int u, v;
			char op;
			scanf("%d %c %d", &u,&op,&v);
			round[i].setNode(u, v, op);
		}
		memset(isNotJudge, 0, sizeof(isNotJudge));
		memset(sentence, 0, sizeof(sentence));
		for (int i = 0; i < n; i++)	//枚举裁判
		{
     
			init(n);	//每次枚举都要初始化并查集,一开始把他放枚举裁判循环外了
			for (int j = 0; j < m; j++)
			{
     
				int u = round[j].u, v = round[j].v, r = 3 - round[j].r;	//3-r才是v->u的关系
				if (u == i || v == i)continue;	//跳过裁判的话	
				if (find(u) == find(v)) {
     
					if ((ral[u] +  r) % 3 != ral[v]) {
     
						isNotJudge[i] = 1;
						sentence[i] = j + 1;	//记录下第几条语句发现错误
						break;
					}
				}
				else Unite(u, v, r);
			}
		}
		int cnt = 0, jud, num = 0;
		for (int i = 0; i < n; i++)
		{
     
			if (sentence[i] > sentence[num])num = i;	//发现关系矛盾,需要最多的语句
			if (!isNotJudge[i]) {
     
				cnt++;	//记录满足裁判的个数
				jud = i;	//当只有一个裁判时,需要输出
			}
		}
		if(cnt==0)printf("Impossible\n");
		else if(cnt>1)printf("Can not determine\n");
		else printf("Player %d can be determined to be the judge after %d lines\n", jud, sentence[num]);
	}
	return 0;
}

你可能感兴趣的:(并查集,OJ题解)