POJ_3648 Wedding 2-Sat

http://poj.org/problem?id=3648

题意:有N-1对夫妻去参加0号夫妻的婚礼,0号新娘和0号新郎分做桌子的两边,现在已知同一对夫妻不能做在同 一边,而且给出M对“通奸”关系,要求这M对人不能有任意一对人同时做在新郎这一边,问是否有解, 有解则输出解。

思路:2-Sat问题。建图的方法是:0号夫妻中,新郎必须在选,也就是说不能选新娘,我们就可以在新娘和新郎之间加一条边,说明要是选了新娘就必要选新郎,这样就会导致矛盾,同时也就间接地规定不能选新娘了。对于其他的通奸关系(i,j),我们可以建图:(i , j') 和 ( j , i' )。 最后用2-Sat求解即可。

代码:

#include<stdio.h>
#include<string.h>
const int MAXN = 70*2 ;
int N ,M ;
int Gv[MAXN*MAXN] , Gnext[MAXN*MAXN] , Gr[MAXN] , Gc ;
int dfn[MAXN] , low[MAXN] , stack[MAXN] , belong[MAXN] , cf[MAXN];
bool in[MAXN] ;
int top , idx , Bcnt ;
int gv[MAXN*MAXN] ,gnext[MAXN*MAXN] , gr[MAXN] , gc ;
int degree[MAXN] ,que[MAXN] ,front ,rear , col[MAXN];

void init(){
    memset(Gr, -1, sizeof(Gr)); Gc = 0 ;
}
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( dfn[u] == low[u] ){
        Bcnt ++ ;
        do{
            v = stack[top--] ; in[v] = 0 ;
            belong[v] = Bcnt ;
        }while(u != v) ;
    }
}
void add2(int a, int b){
    gv[gc] = b ;
    gnext[gc] = gr[a] ;
    gr[a] = gc++ ;
}
void solve(){
    memset(gr , -1,  sizeof(gr)); gc = 0 ;
    memset(degree , 0 ,sizeof( degree) ) ;
    for(int i=1;i<=2*N;i++){
        for(int j=Gr[i] ;j!=-1;j=Gnext[j]){
            int v = Gv[j] ;
            int fa = belong[i] ;
            int fb = belong[v] ;
            if( fa != fb){
                add2(fb ,fa);
                degree[fa] ++ ;
            }
        }
    }
    front = rear = 0 ;
    for(int i=1;i<=Bcnt;i++){
        if( degree[i] == 0)  que[rear++] = i ;
    }
    memset(col , 0 ,sizeof(col));
    while(front != rear){
        int v = que[front++] ;
        if( col[v] == 0 ){
            col[v] = 1 ;
            col[ cf[v] ] = -1 ;
        }
        for(int i=gr[v];i!=-1;i=gnext[i]){
            int u = gv[i] ;
            if( --degree[u] == 0)   que[rear++]  = u ;
        }
    }
    bool first = 1 ;
    for(int i=1;i<=N;i++){
        if(first == 0)  printf(" ");
        first = 0 ;
        if( col[ belong[2*i-1] ] == -1 ){
            printf("%dw",i);
        }
        else
            printf("%dh",i);
    }
    printf("\n");
}
int main(){
    int a, b ,c , d ;
    char ch1, ch2 ;
    while(scanf("%d%d",&N,&M) == 2){
        if(0==N && M==0)    break ;
        init() ;
        for(int i=1;i<=M;i++){
            scanf("%d%c %d%c",&a,&ch1,&b,&ch2);
            if(a == b)  continue ;
            if( ch1=='h' ){
                c = 2 * a -1 ; a = 2 * a ;
            }
            else{
                c = 2 * a ; a = 2 * a - 1 ;
            }
            if( ch2=='h' ){
                d = 2 * b - 1 ; b = 2 * b ;
            }
            else{
                d = 2 * b;  b = 2 * b - 1 ;
            }
            if(a==0){
                if(ch1=='h'){
                    add(b,d);
                }
                else    continue ;
            }
            else if(b == 0){
                if(ch2=='h'){
                    add(a,c);
                }
                else
                    continue ;
            }
            else{
                add(a,d);
                add(b,c);
            }
        }
        N-- ;
        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);
        }
        bool ok = 1 ;
        for(int i=1;i<=N;i++){
            if( belong[2*i-1] == belong[2*i] ){
                ok = 0 ; break ;
            }
            cf[ belong[2*i-1] ] = belong[2*i] ;
            cf[ belong[2*i] ] = belong[2*i-1] ;
        }
        if(!ok){
            printf("bad luck\n");   continue ;
        }
        solve() ;
    }
    return 0 ;
}


你可能感兴趣的:(POJ_3648 Wedding 2-Sat)