题目链接:http://poj.org/problem?id=1291
题意:
给出n句话,
形如“第x句话是错误的”或“第x句话是正确的”。
判断是否有合法结果。
若有,计算至多有多少句话是正确的。
算法:
典型的并查集。
对于每个节点,维护与父节点的距离d[x],
同一并查集内,
相对距离为偶数的节点共真假。
每处理一条关系,
若这两句话不在一个集合内,
则通过这两句话间的相对距离(若同奇偶即为0,不同奇偶即为1)计算两根节点间的相对距离,然后合并。
若这两句话在一个集合内,
则判断两节点目前的相对距离是否与这条关系矛盾,
若矛盾即无结果。
计算结果时,
对于同一个集合中,d[x]为奇的划为一类,为偶的划为一类,取每个集合中数量较多的一类相加就可以。
——————————以下是废话的分界线——————————
本题实际是一个标准的2-SAT模型。
并查集的做法,相当于建立一个无向图模型。
对于一句话,
若形如“第x句话是错误的”,则在两点间建一条长度为1的边,
若形如“第x句话是正确的”,则在两点间建一条长度为0的边。
无向图模型中的一条边相当于2-SAT模型中的4条边。
在实际计算中,距离的具体长度是我们所不关心的,
距离的奇偶性才是我们应该关心的。
所以可以将距离对2取余。
实际上每个联通块,被缩成了两个点,这两个点中的句子不同真假。
也就是说,若只考虑长度为奇数的边,那么每一个联通块都构成了一个二部图。
至此,并查集的做法与2-SAT模型的联系就体现了出来。
显然,若图中存在奇圈,则无解。
因为奇圈相当于,两点间存在两条长度奇偶性不同的路线。
所以必定不存在合法方案。
代码如下:
int变量版:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=1100;
int p[MAXN],d[MAXN],cot[2][MAXN];
int findp(int x) {
if(p[x]==-1) {
return x;
}
int ret=findp(p[x]);
d[x]=(d[x]+d[p[x]])&1;
return p[x]=ret;
}
int main() {
int n;
while(scanf("%d",&n),n) {
memset(p,-1,sizeof(p));
memset(d,0,sizeof(d));
bool flg=true;
for(int x=0; x<n; x++) {
int y;
char s[100];
scanf("%s%d%s%s",s,&y,s,s);
y--;
int px=findp(x);
int py=findp(y);
int ret;
if(s[0]=='t') {
ret=0;
} else {
ret=1;
}
if(px!=py) {
d[py]=(d[x]+d[y]+ret)&1;
p[py]=px;
} else {
if(((d[x]+d[y])&1)!=ret) {
flg=false;
}
}
}
if(!flg) {
puts("Inconsistent");
} else {
int ans=0;
memset(cot,0,sizeof(cot));
for(int i=0; i<n; i++) {
int px=findp(i);
cot[d[i]&1][px]++;
}
for(int i=0; i<n; i++) {
ans+=max(cot[0][i],cot[1][i]);
}
printf("%d\n",ans);
}
}
return 0;
}
bool变量版:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=1100;
int p[MAXN],cot[2][MAXN];
bool d[MAXN];
int findp(int x) {
if(p[x]==-1) {
return x;
}
int ret=findp(p[x]);
d[x]^=d[p[x]];
return p[x]=ret;
}
int main() {
int n;
while(scanf("%d",&n),n) {
memset(p,-1,sizeof(p));
memset(d,0,sizeof(d));
bool flg=true;
for(int x=0; x<n; x++) {
int y;
char s[100];
scanf("%s%d%s%s",s,&y,s,s);
y--;
int px=findp(x);
int py=findp(y);
bool ret;
if(s[0]=='t') {
ret=false;
} else {
ret=true;
}
if(px!=py) {
d[py]=d[x]^d[y]^ret;
p[py]=px;
} else {
if(d[x]^d[y]^ret) {
flg=false;
}
}
}
if(!flg) {
puts("Inconsistent");
} else {
int ans=0;
memset(cot,0,sizeof(cot));
for(int i=0; i<n; i++) {
int px=findp(i);
cot[d[i]?1:0][px]++;
}
for(int i=0; i<n; i++) {
ans+=max(cot[0][i],cot[1][i]);
}
printf("%d\n",ans);
}
}
return 0;
}