zoukankan      html  css  js  c++  java
  • POJ 3648 Wedding(2-sat)

    Wedding
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 6673   Accepted: 2033   Special Judge

    Description

    Up to thirty couples will attend a wedding feast, at which they will be seated on either side of a long table. The bride and groom sit at one end, opposite each other, and the bride wears an elaborate headdress that keeps her from seeing people on the same side as her. It is considered bad luck to have a husband and wife seated on the same side of the table. Additionally, there are several pairs of people conducting adulterous relationships (both different-sex and same-sex relationships are possible), and it is bad luck for the bride to see both members of such a pair. Your job is to arrange people at the table so as to avoid any bad luck.

    Input

    The input consists of a number of test cases, followed by a line containing 0 0. Each test case gives n, the number of couples, followed by the number of adulterous pairs, followed by the pairs, in the form "4h 2w" (husband from couple 4, wife from couple 2), or "10w 4w", or "3h 1h". Couples are numbered from 0 to n - 1 with the bride and groom being 0w and 0h.

    Output

    For each case, output a single line containing a list of the people that should be seated on the same side as the bride. If there are several solutions, any one will do. If there is no solution, output a line containing "bad luck".

    Sample Input

    10 6
    3h 7h
    5w 3w
    7h 6w
    8w 3w
    7h 3w
    2w 5h
    0 0
    

    Sample Output

    1h 2h 3w 4h 5h 6h 7h 8h 9h
    

    Source

    【题目大意】

    此题题意很有意思。一堆夫妇去参加一对新人的婚礼。人们坐在一个很长很长的桌子的两侧(面对面)。新郎新娘在桌子头面对面座。

    新娘不希望看见她对面的一排有一对夫妇坐着(夫妇需要分开两排座)。

    同时,一些人之间有通奸关系,新娘也不希望有通奸关系的人同时坐在她对面的一排。

    问你可否满足新娘的要求,可以的话,输出一种方案

    【解题思路】

     把丈夫和新娘同一边看做点i,在新娘对面看做i+n。然后根据通奸关系进行构图。因为新郎也有可能有通奸关系,
     所以构图时加入新郎点0,增加一条边,0-->0+n。然后就是求解2-SAT问题了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    const int VM=210;
    const int EM=10010;
    
    struct Edge{
        int frm,to,nxt;
    }edge1[EM<<1],edge2[EM<<1];
    
    int n,m,cnt1,cnt2,dep,top,atype,head1[VM],head2[VM];
    int dfn[VM],low[VM],vis[VM],belong[VM],indeg[VM];
    int stack[VM],ans[VM],mark[VM],color[VM],que[VM];   //color[]为是否选择标志 //1表示选择,0表示不选择
    
    void Init(){
        cnt1=0, cnt2=0,  atype=0,    dep=0,  top=0;
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        memset(vis,0,sizeof(vis));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(belong,0,sizeof(belong));
        memset(indeg,0,sizeof(indeg));
        memset(ans,0,sizeof(ans));
        memset(mark,0,sizeof(mark));
        memset(color,0,sizeof(color));
    }
    
    void addedge1(int cu,int cv){   //原图增加一条边
        edge1[cnt1].frm=cu;     edge1[cnt1].to=cv;    edge1[cnt1].nxt=head1[cu];
        head1[cu]=cnt1++;
    }
    
    void addedge2(int cu,int cv){   //缩点图增加一条边
        edge2[cnt2].frm=cu;     edge2[cnt2].to=cv;    edge2[cnt2].nxt=head2[cu];
        head2[cu]=cnt2++;
    }
    
    void Tarjan(int u){     //Tarjan算法求强连通分量
        dfn[u]=low[u]=++dep;
        stack[top++]=u;
        vis[u]=1;
        for(int i=head1[u];i!=-1;i=edge1[i].nxt){
            int v=edge1[i].to;
            if(!dfn[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        int j;
        if(dfn[u]==low[u]){
            atype++;
            do{
                j=stack[--top];
                belong[j]=atype;
                vis[j]=0;
            }while(u!=j);
        }
    }
    
    int solve(){
        for(int i=0;i<2*n;i++)
            if(!dfn[i])
                Tarjan(i);
        for(int i=0;i<n;i++){
            if(belong[i]==belong[i+n])      //若有同一组的分量在同一个强连通分量中,则直接返回false
                return false;
            mark[belong[i]]=belong[i+n];    //存储同一组的分量所在哪个强连通分量,这样访问过其中一个后,另一个就不用再去访问了
            mark[belong[i+n]]=belong[i];    //在缩点的图中标记互斥的缩点。(原来互斥,现在也互斥)
        }
        for(int i=0;i<cnt1;i++)     //cnt1条边,建立缩点图
            if(belong[edge1[i].frm]!=belong[edge1[i].to]){
                addedge2(belong[edge1[i].to],belong[edge1[i].frm]);     //反向,是因为u--->v,如果选择了u,必须选择v,则应该反向,求入度为0的缩点
                indeg[belong[edge1[i].frm]]++;       //统计入度
            }
    
        int head=1,tail=1;      //拓扑排序求解
        for(int i=1;i<=atype;i++)
            if(indeg[i]==0)     //入度为0入队列
                que[tail++]=i;
        while(head<tail){
            int u=que[head++];
            if(color[u]==0){         //对于未着色的点x,将x染成红色1,同时将与x矛盾的点cf[x]染成蓝色-1。
                color[u]=1;
                color[mark[u]]=-1;
            }
            for(int i=head2[u];i!=-1;i=edge2[i].nxt){
                int v=edge2[i].to;
                if(--indeg[v]==0)    //入度为0
                    que[tail++]=v;      //入队列
            }
        }
        for(int i=0;i<n;i++)
            if(color[belong[i]]==1)
                ans[i]=1;
        return true;
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        char ch1,ch2;
        while(~scanf("%d%d",&n,&m)){
            Init();
            int u,v;
            while(m--){
                scanf("%d%c %d%c",&u,&ch1,&v,&ch2);
                if(ch1=='h' && ch2=='h'){   //开始构图
                    addedge1(u+n,v);
                    addedge1(v+n,u);
                }else if(ch1=='h' && ch2=='w'){
                    addedge1(u+n,v+n);
                    addedge1(v,u);
                }else if(ch1=='w' && ch2=='h'){
                    addedge1(u,v);
                    addedge1(v+n,u+n);
                }else if(ch1=='w' && ch2=='w'){
                    addedge1(u,v+n);
                    addedge1(v,u+n);
                }
            }
            addedge1(0,0+n);       //增加新娘到新郎的边
            if(solve()){
                for(int i=1;i<n;i++){
                    if(ans[i])
                        printf("%dh ",i);
                    else
                        printf("%dw ",i);
                }
                printf("
    ");
            }else
                printf("bad luck
    ");
        }
        return 0;
    }
  • 相关阅读:
    常见中外出版社
    OpenCL编程基本流程及完整示例
    OpenCL基本概念
    matlab 高阶(三)—— 插值(fft、)
    matlab 高阶(三)—— 插值(fft、)
    matlab 小波处理工具箱
    matlab 小波处理工具箱
    小波图像处理 —— 奇异点(不连续点)检测
    (step6.1.5)hdu 1233(还是畅通工程——最小生成树)
    Android基础总结(精华完整版)
  • 原文地址:https://www.cnblogs.com/jackge/p/3180206.html
Copyright © 2011-2022 走看看