[POJ3648] 参加婚礼

Description
一对新婚的夫妇邀请(n-1)对夫妇来参加自己的婚礼宴会,这对新人以及这些受邀请的夫妇都坐在一张长桌子的两测,新娘和新郎分别坐在桌子的两侧的顶端。新娘不希望看到她邀请来的那些夫妇之中有妻子和丈夫坐在同一侧的情况(即妻子和丈夫要分坐在桌子的两侧),在这n对夫妇中有一些男女存在着暧昧的关系(可能是同性之间也可能是异性之间),所以新娘也不希望看到有暧昧关系的人坐在她对面的那一侧。
求解是否存在一种满足新娘要求的座位分配方案,如果存在的话,就输出这方案,否则输出”bad luck”。

Input
输入包含多组测试数据,整个输入以一行”0 0”结束。每组测试数据:
第一行两个整数n和m,分别表示夫妇的对数(包括新婚夫妇)和有暧昧关系的对数;
接下来m行,每行用形如”ah bw”或”ah bh”或”aw bw”(1≤a、b≤n-1)表示第a对夫妇的丈夫,第b对夫妇的妻子有暧昧关系,新婚夫妇的编号为0。

Output
对于每组测试数据输出一行,若存在一种满足要求的座位分配方案,则输出坐在新娘这一侧的座位方案(按编号顺序输出);若无解就输出”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

Hint
100%的数据:n≤30。

【题意】:有一对新人结婚,邀请n对夫妇去参加婚礼。
有一张很长的桌子,人只能坐在桌子的两边,还要满
足下面的要求:1.每对夫妇不能坐在同一侧 2.n对夫妇
之中可能有通奸关系(包括男男,男女,女女),有通
奸关系的不能同时坐在新娘的对面,可以分开坐,可以
同时坐在新娘这一侧。如果存在一种可行的方案,输出
与新娘同侧的人。

写的第二道2-SAT
感觉这题还是有点难的,也比较烦
2-SAT时选择和新郎一边的人 这样比较好判断
同时再连一条新娘到新郎的边 表示新郎必须选
然后就是裸的2-SAT了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;

const int MaxN=65;
const int MaxM=10005;

int N,M,Cnt,EdgeCnt;
int Tot,Head[MaxN],Next[MaxM],To[MaxM];
int Index,DFN[MaxN],Low[MaxN];
int Top,Stack[MaxN],ID[MaxN];
bool Vis[MaxN];
int Out[MaxN],Q[MaxN];
int G[MaxN],Ans[MaxN];

struct Edge{
    int u,v;
}E[MaxM];

vector<int> V[MaxN],A;

void Add_Edge(int u,int v){
    E[++EdgeCnt]=(Edge){u,v};
    Next[++Tot]=Head[u];
    To[Tot]=v;
    Head[u]=Tot;
}

void Init(){
    int i,j,a,b;
    char c1,c2;
    memset(Head,0,sizeof(Head));
    Tot=EdgeCnt=Cnt=0;
    for(i=1;i<=M;i++){
        scanf("%d%c %d%c\n",&a,&c1,&b,&c2);
        a=a*2+(c1=='w'),b=b*2+(c2=='w');
        Add_Edge(a,b^1);
        Add_Edge(b,a^1);
    }
    Add_Edge(1,0);
}

void DFS(int u){
    int i,v,tmp;
    DFN[u]=Low[u]=++Index;
    Vis[Stack[++Top]=u]=true;
    for(i=Head[u];i;i=Next[i])  
        if(!DFN[v=To[i]]){
            DFS(v);
            Low[u]=min(Low[u],Low[v]);
        }
        else if(Vis[v])
            Low[u]=min(Low[u],DFN[v]);
    if(DFN[u]==Low[u]){
        Cnt++;
        do{
            tmp=Stack[Top--];
            ID[tmp]=Cnt;
            Vis[tmp]=false;
        }while(tmp!=u);
    }
}

void Work(){
    int i,u,h=1,t=0;
    Top=Index=0;
    memset(DFN,0,sizeof(DFN));
    memset(Low,0,sizeof(Low));
    memset(Vis,false,sizeof(Vis));
    for(i=0;i<N*2;i++)
        if(!DFN[i])
            DFS(i);
    memset(G,0,sizeof(G));
    for(i=0;i<N*2;i+=2){
        if(ID[i]==ID[i+1]){
            puts("bad luck");
            return;
        }
        G[ID[i]]=ID[i+1];
        G[ID[i+1]]=ID[i];
    }
    for(i=1;i<=Cnt;i++)
        V[i].clear();
    memset(Out,0,sizeof(Out));
    for(i=1;i<=EdgeCnt;i++)
        if(ID[E[i].u]!=ID[E[i].v]){
            V[ID[E[i].v]].push_back(ID[E[i].u]);
            Out[ID[E[i].u]]++;
        }
    memset(Q,-1,sizeof(Q));
    memset(Ans,0,sizeof(Ans));
    for(i=1;i<=Cnt;i++)
        if(!Out[i])
            Q[++t]=i;
    while(h<=t){
        u=Q[h++];
        if(!Ans[u])
            Ans[u]=1,Ans[G[u]]=-1;
        for(i=0;i<V[u].size();i++)
            if(!(--Out[V[u][i]]))
                Q[++t]=V[u][i];
    }
    A.clear();
    for(i=2;i<N*2;i++)
        if(Ans[ID[i]]==-1)
            A.push_back(i);
    for(i=0;i<A.size()-1;i++)
        printf("%d%c ",A[i]>>1,A[i]&1?'w':'h');
    printf("%d%c\n",A[i]>>1,A[i]&1?'w':'h');
}

int main(){
    while(scanf("%d%d",&N,&M)&&N){
        Init();
        Work();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值