【GOJ 1461】Liars and Truth Tellers

题目

正解

这道题类似于 食物链,但比这道题简单。

我们可以维护一个有 (2n) 个节点的并查集,理解时分成两个区间 ([1,n],[n+1,2n])。每个区间的对应值((i)(n+i))属于一种对立关系,一真一假,排好可能的正反两种情况。所以这两个数不能属于同一连通块

接下来就很简单了。我们在它输入时同时进行处理、判断。当两个对应点属于同一个连通块时,那肯定不行,跳出。

代码

#include<bits/stdc++.h>
using namespace std;
int f[2005];
int getf(int k) {
	if(f[k]==k) {
		return k;
	}
	return f[k]=getf(f[k]);
}
void merge(int u,int v) {
	u=getf(u),v=getf(v);
	if(u!=v) {
		f[u]=v;
	}
}
int main() {
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1; i<=n*2; i++) {
		f[i]=i;
	}
	for(int k=1; k<=m; k++) {
		int x,y;
		char c[3];
		scanf("%d %d %s",&x,&y,c);
		if(!strcmp(c,"T")) {
			merge(x,y),merge(x+n,y+n);
		} else {
			merge(x,y+n),merge(x+n,y);
		}
		for(int i=1; i<=n; i++) {
			if(getf(i)==getf(i+n)) {
				printf("%d",k-1);
				return 0;
			}
		}
	}
	printf("%d",m);
	return 0;
}

后记

  1. 如果代码一直有问题时,在很清楚的知道这道题的知识点、方向、思路正确的前提下,并且代码实现并不复杂,可以考虑重写代码,说不定有惊喜~

  2. 如果有相似模块需要更改后重新调用,在空间充裕的前提下可以采用命名空间(namespace)来规避名字污染、初始化不到位等情况。

  3. 如果要输入字符,建议以输入字符串的形式进行。

原文地址:https://www.cnblogs.com/Sam2007/p/13362359.html