题目链接: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; }