首页 > 其他 > 详细

poj-3648(2-sat)

时间:2019-03-27 22:16:25      阅读:180      评论:0      收藏:0      [点我收藏+]

题目链接:http://poj.org/problem?id=3648

题意:有n对夫妻坐成两排,其中第0对为新娘新郎。有m对奸情,新娘不愿意看到对面排存在奸情,问是否有合理方案,有输出一组解,否则输出"bad luck";

 

思路:

每对夫妻要么和新郎一排,要么和新娘一排所以容易想到用2-sat.

我们将丈夫编号为0~n-1,其对应的妻子编号+n(下面用i表示丈夫,i‘表示妻子).

每对奸情则即是矛盾,则与其不矛盾的点连边,比如a与b矛盾,则连a->b‘,b->a‘,其意思是选a必须连b‘,不能选b。

 

这里用一个数组(kx[])表示该点是否可选,或没被选。 初始值为0,表示未被选,1表示可选及已选,-1表示不可选。

每次选择了一个点后,就暴力搜接下来必须选择的点,然后把他们都选择,其伴侣都标记为不选择。如果不合法就换一种方式搜。

 

连边时要加一条新娘到新郎的边,因为新郎也可能有奸情,使其矛盾。

过程例如以下:a与新郎有奸情,矛盾,在开始建图时会使a->新娘,当如果爆搜选了a,则下面选新娘,标记新郎不可选,再通过建的这条边,发现爆搜a不可行,这样就避免了新郎与奸情坐一侧,这点很重要,而且我想了很久很久。。。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node{
    int u,v,next;
}e[maxn];
int head[maxn],kx[maxn],n,m,top,cnt,st[maxn];
//kx数组判断是否可选,初始值为0, 1为可选且已选,-1为不可选。 
int cp(int x){ return x<=n?x+n:x-n; }//返回cp编号 
void add(int u,int v){e[cnt].u=u,e[cnt].v=v,e[cnt].next=head[u],head[u]=cnt++;}

bool dfs(int x)//爆搜,判断编号x是否可选 
{
    if(kx[x]==1)    return true;//可选,且已被选。 
    if(kx[x]==-1)    return false;//不可选 
    kx[x]=1,kx[cp(x)]=-1,st[++top]=x;//没被选,但是可被选,所以选入,其cp标为不可选。 
    for(int i=head[x];i!=-1;i=e[i].next)
    {
        if(!dfs(e[i].v))//判断相连的点是否可选,要选一起选。 
            return false;
    }
    return true;
}

void solve()
{
    for(int i=1;i<=n;i++)
    {
        if(kx[i])//由0~i-1 连边判断已被选,不用进行下面操作    
            continue;
        top=0;
        if(!dfs(i))//kx[i]==0,没被选 ,且不可选 
        {
            while(top)//返回由i推到已选点,重新变成没选状态。 
            {
                kx[st[top]]=kx[cp(st[top])]=0;
                top--;
            }
            if(!dfs(i+n))//i不可选,且i+n也不可选,说明寻找不到答案。 
            {
                cout<<"bad luck"<<endl;
                return ;    
            }    
        }
    }    
    for(int i=1;i<n;i++)//可以找到解 
    {
        if(kx[i]==-1)//当i不可选,则表示新娘不可见,放到新娘一边 
            cout<<i<<"h ";
        else//否则i+n不可选,所以i的妻子放在新娘一边 
            cout<<i<<"w ";
    }
    cout<<endl;
}

int main()
{
    std::ios::sync_with_stdio(false);
    int x,y;
    char x1,y1;
    while(cin>>n>>m)
    {
        if(!n&&!m)    break;    
        memset(kx,0,sizeof(kx));
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=0;i<m;i++)
        {
            cin>>x>>x1>>y>>y1;
            if(!x) x=n;
            if(!y) y=n;
            if(x1==h&&y1==h)        add(x,y+n),add(y,x+n);
            else if(x1==h&&y1==w)    add(x,y),add(y+n,x+n);
            else if(x1==w&&y1==h)    add(x+n,y+n),add(y,x);
            else if(x1==w&&y1==w)    add(x+n,y),add(y+n,x);
        }
        add(2*n,n);//加一条新娘到新郎的边,因为新郎可能有奸情 
        solve();
    }    
    return 0;
}

 

poj-3648(2-sat)

原文:https://www.cnblogs.com/xiongtao/p/10611026.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!