poj3648Wedding【2-SAT】输出任意解

本文介绍了一种使用2-SAT算法解决婚礼宴会上的座位安排问题的方法,确保不会出现不良组合,如夫妻坐同一侧或通奸者被新娘同时看到的情况。

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

Total Submissions: 9574

  Accepted: 2908 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


题意:

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

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

同时,一些人之间有通奸关系(通奸不分性别,而且新郎新娘也可能通奸!!!!),新娘也不希望有通奸关系的人同时坐在她对面的一排。

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

做法:和hdu1814Peaceful Commission【2-SAT】输出最小解   一模一样,实在不理解为啥非得强连通分量缩点,反向拓扑排序……

这个题套入2-sat的真假有点绕,我们假设新娘这侧选h是“真”(i),选"w"是假(i+n),那么h-h加边就是b+n->a a+n->b ; w-h : a->b  b+n->a+n ; w-w : a->b+n  b->a+n ; h-w : b->a a+n->b+n

还有据说新郎也可能和别人通奸,新娘设为0,新郎设成n,再连一个0->n(他俩位置得固定下来啊,,,这么连边也满足我上面的推理)

注意不要用%s,貌似数据的通奸关系中间可能没有空格

还有就是和hdu1814一样的问题,if条件写一个写两个都对,我感觉应该写两个啊==

/*************
poj3648
2016.7.27
452K	0MS	C++	2038B
************/
#include <iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
#define maxn 8004
struct TWOSAT
{
    int n;
    vector<int>G[maxn*2];
    bool mark[maxn*2];
    int S[maxn*2],c;
    bool dfs(int x)
    {
        if(mark[x+n])return false;
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for(int i=0;i<G[x].size();i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n*2;i++) G[i].clear();
        memset(mark,0,sizeof(mark));
    }
    void add_clause(int x,int y)
    {
        G[x].push_back(y);
       // G[y].push_back(x);///不一定是+1、-1!!而且本身就2n不用乘以2
    }
    bool solve()
    {
        for(int i=0;i<n;i++)
        {
            if(!mark[i]&&!mark[i+n])
            {
                c=0;
                if(!dfs(i))
                {
                    while(c>0) mark[S[--c]]=false;
                    if(!dfs(i+n)) return false;
                }
            }
        }
        return true;
    }
}solver;
int n,m;

int main()
{
   // freopen("cin.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        solver.init(n);
        for(int i=0;i<m;i++)
        {
            int a,b;
            char c1,c2;
            scanf("%d%c%d%c",&a,&c1,&b,&c2);
            if(c1=='h'&&c2=='h')
                solver.add_clause(a+n,b),solver.add_clause(b+n,a);
            if(c1=='h'&&c2=='w')
                solver.add_clause(a+n,b+n),solver.add_clause(b,a);
            if(c1=='w'&&c2=='h')
                solver.add_clause(a,b),solver.add_clause(b+n,a+n);
            if(c1=='w'&&c2=='w')
                solver.add_clause(a,b+n),solver.add_clause(b,a+n);
        }
        solver.add_clause(0,n);
        if(!solver.solve()) puts("bad luck");
        else
        {
            for(int i=1;i<n;i++)
            {
                if(solver.mark[i]&!solver.mark[i+n]) printf("%dh ",i);
                //452K	16MS	C++	2122B if后面的条件加上的话
                else printf("%dw ",i);
            }
            puts("");
        }
    }
    return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值