poj3648 Wedding(2 SAT)

通过构建图论模型解决一对新人在婚礼上如何安排宾客座位的问题,确保遵循特定规则,包括夫妇不能坐在同一侧、存在通奸关系者不坐对面等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意:
有一对新人结婚,邀请n对夫妇去参加婚礼
有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:

  1. 每对夫妇不能坐在同一侧
  2. n对夫妇之中可能有通奸关系,有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧
  3. 新郎新娘不能坐在同一侧

如果存在一种可行的方案,输出与新娘同侧的人

分析:
题目描述真的是。。。

我们构造一个图,选出要坐在新娘对面的人
设夫妇为 (h1,w1),(h2,w2) ( h 1 , w 1 ) , ( h 2 , w 2 )

如果 h1,h2 h 1 , h 2 存在矛盾: h1>w2,h2>w1 h 1 − > w 2 , h 2 − > w 1
如果 h1,w2 h 1 , w 2 存在矛盾: h1>h2,w2>w1 h 1 − > h 2 , w 2 − > w 1
如果 w1,h2 w 1 , h 2 存在矛盾: w1>w2,h2>h1 w 1 − > w 2 , h 2 − > h 1
如果 w1,w2 w 1 , w 2 存在矛盾: w1>h2,w2>h1 w 1 − > h 2 , w 2 − > h 1

同时添加一条边,连接新娘到新郎,表示必须选新郎坐在新娘对面

对图染色,输出与新娘颜色相同的人

还是要注意编号从0开始

tip

0是新娘,1是新郎
偶数妻子,奇数丈夫
不要忘了初始化

代码是最小解

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=20010;
int n,m,st[N<<1],tot=0,top,s[N<<1];
struct node{
    int y,nxt;
};
node way[N<<2];
bool col[N<<1];

void add(int u,int w) {
    tot++;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
}

int fan(int x) {
    if (x&1) return x-1;
    else return x+1;
}

bool paint(int x) {
    if (col[x]) return 1;
    if (col[fan(x)]) return 0;
    col[x]=1;
    s[++top]=x;
    for (int i=st[x];i;i=way[i].nxt)
        if (!paint(way[i].y)) return 0;
    return 1;
}

bool solve() {
    memset(col,0,sizeof(col));
    for (int i=0;i<2*n;i+=2)
        if (!col[i]&&!col[i+1]) {
            top=0;
            if (!paint(i)) {
                while (top) col[s[top--]]=0;
                if (!paint(i+1)) return 0;
            }
        }
    return 1;
}

int main()
{
    int a,b;
    char s1[2],s2[2];
    while (scanf("%d%d",&n,&m)!=EOF&&n+m) {        //h 2*n+1 w 2*n
        memset(st,0,sizeof(st)); tot=0;

        for (int i=1;i<=m;i++) {
            scanf("%d%s %d%s",&a,s1,&b,s2);
            if (s1[0]=='h'&&s2[0]=='h') {
                add(a*2+1,b*2); add(b*2+1,a*2);
            }
            else if (s1[0]=='h'&&s2[0]=='w') {
                add(a*2+1,b*2+1); add(b*2,a*2);
            }
            else if (s1[0]=='w'&&s2[0]=='h') {
                add(a*2,b*2); add(b*2+1,a*2+1);
            }
            else {
                add(a*2,b*2+1); add(b*2,a*2+1);
            }
        }
        add(0,1);
        if (solve()) {
            bool f=col[0];     //与新娘同侧
            for (int i=2;i<n*2;i+=2)
                if (col[i]==f) printf("%dw ",i/2);
                else printf("%dh ",i/2);
            printf("\n");
        }
        else printf("bad luck\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值