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 <cstdio>
#include<cstring>
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章