http://acm.hdu.edu.cn/showproblem.php?pid=1824
题意:
acm集训队有N只队伍,每只队伍有3人,其中1人为队长,另外两人都队员,
现在需要安排回家休息,每只队伍要么队长回家,要么两名队员同时回家休息。 给
出M组队员的信息,每组为(a,b)表示的是队员a和队员b不能同时留下也不能同时回
家,问是否存在可行的方案。
思路:
2-Sat问题,对于每个队,留校的要么是队长,要么是两个队员,因此这就是典型
的2-Sat模型,可以将两个队员看成是一个点,建图就是按照题目中给的信息来建,
最后用tarjin缩点并判断是否存在解即可。
代码:
#include<stdio.h>
#include<string.h>
int N ,M ;
int a1[1010] , a2[2][1010] ;
int nn[3*1010] ;
int be[3*1010] ;
const int MAXN = 1010*2 ;
int Gr[MAXN] , Gv[MAXN*MAXN] , Gnext[MAXN*MAXN] , Gc ;
int fa[MAXN] ;
int dfn[MAXN] , low[MAXN] , stack[MAXN] , belong[MAXN] ;
bool in[MAXN] ;
int top, idx ,Bcnt ;
void add(int a, int b){
Gv[Gc] = b ;
Gnext[Gc] = Gr[a] ;
Gr[a] = Gc++ ;
}
void tarjin(int u){
int v ;
low[u] = dfn[u] = ++idx ;
stack[++top] = u ; in[u] = 1 ;
for(int i=Gr[u] ;i!=-1;i=Gnext[i]){
v = Gv[i] ;
if( !dfn[v] ){
tarjin(v) ;
if( low[v] < low[u] ) low[u] = low[v] ;
}
else if( in[v] && dfn[v]<low[u])
low[u] = dfn[v] ;
}
if( low[u] == dfn[u] ){
Bcnt++ ;
do{
v = stack[top--] ; in[v] = 0 ;
belong[v] = Bcnt ;
}while(u != v) ;
}
}
bool solve(){
top = idx = Bcnt = 0 ;
memset(dfn, 0, sizeof(dfn));
memset(in, 0 ,sizeof(in));
for(int i=1;i<=2*N;i++){
if( !dfn[i] ) tarjin(i) ;
}
for(int i=1;i<=N;i++){
if( belong[i] == belong[i+N]) return false ;
}
return true ;
}
int main(){
int a ,b ,c ;
while(scanf("%d%d",&N,&M) == 2){
memset(be, -1,sizeof(be));
memset(fa, -1, sizeof(fa));
for(int i=1;i<=N;i++){
scanf("%d%d%d",&a1[i],&a2[0][i],&a2[1][i]);
fa[ a1[i] ] = a1[i] ;
fa[ a2[0][i] ] = a2[0][i] ;
fa[ a2[1][i] ] = a2[0][i] ;
nn[ a1[i] ] = i ;
nn[ a2[0][i] ] = i + N ;
}
memset(Gr,-1, sizeof(Gr)); Gc = 0 ;
for(int i=1;i<=M;i++){
scanf("%d%d",&a,&b);
int aa = fa[a] ;
int bb = fa[b] ;
int na = nn[aa] ;
int nb = nn[bb] ;
int oa ,ob ;
if(na > N) oa = na - N ;
else oa = na + N ;
if(nb > N) ob = nb - N ;
else ob = nb + N ;
add(na , ob);
add(nb , oa);
}
if( solve() ) printf("yes\n");
else printf("no\n");
}
return 0 ;
}