码迷,mamicode.com
首页 > 其他好文 > 详细

POJ3648.Wedding——2-sat输出任意解

时间:2015-04-22 13:54:04      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:

http://poj.org/problem?id=3648

题目描述:
有一对新人举办婚礼,邀请了n对夫妇参加他们的婚礼,有一张桌子,人只能坐在桌子的两边。有m对的人通奸(男男,男女,女女),要求:
1.夫妇不能坐在同一边
2.通奸的两个人不能坐在新娘的对面那边

如果存在一组解,则输出坐在新娘同侧的人

分析:
每个人两种状态,坐在桌子的一边或者另一边,有m组矛盾。可以在新郎必选的前提下求出一组解,则这组解为与新郎同侧;反之在新娘必选的前提下求出一组解,则这组解为与新娘同侧。
用2-sat求出一组解,分为值为1和值为0的两部分

//224K  0MS C++
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
const int MAXN=2010;
const int MAXM=1000010;
using namespace std;
int low[MAXN],dfn[MAXN],sccno[MAXN],scc,dfs_clock,top;
int Stack[MAXN];
bool instack[MAXN];
struct Edge {
    int to,next;
} edge[MAXM<<1];int head[MAXN],tot;
void addedge(int u,int v){
    edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void init(){
    tot=0;
    memset(head,0xff,sizeof(head));
}
void dfs(int u){
    int v;
    low[u]=dfn[u]=++dfs_clock;
    instack[u]=1;
    Stack[top++]=u;
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        v=edge[i].to;
        if(!dfn[v]) {
            dfs(v);
            if(low[u]>low[v])
                low[u]=low[v];
        } else if(instack[v]&&low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(low[u]==dfn[u]) {
        scc++;
        for(;;) {
            v=Stack[--top];
            instack[v]=0;
            sccno[v]=scc;
            if(v==u) break;
        }
    }
}
bool solveable(int n){
    memset(dfn,0,sizeof(dfn));
    memset(instack,false,sizeof(instack));
    dfs_clock=top=scc=0;
    for(int i=0; i<n; ++i) {
        if(!dfn[i]) dfs(i);
    }
    for(int i=0; i<n; i+=2) {
        if(sccno[i]==sccno[i^1]) return false;
    }
    return true;
}
queue<int> q1;
vector<vector<int> >dag;
char color[MAXN];
int indeg[MAXN];
int cf[MAXN];
void solve(int n){
    dag.assign(scc+1,vector<int>());
    memset(indeg,0,sizeof(indeg));
    memset(color,0,sizeof(color));
    for(int u=0;u<n;++u){
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(sccno[u]!=sccno[v]){
                dag[sccno[v]].push_back(sccno[u]);
                indeg[sccno[u]]++;
            }
        }
    }
    for(int i=0;i<n;i+=2){
        cf[sccno[i]]=sccno[i^1];
        cf[sccno[i^1]]=sccno[i];
    }
    while(!q1.empty()) q1.pop();
    for(int i=1;i<=scc;++i){
        if(indeg[i]==0) q1.push(i);
    }
    while(!q1.empty()){
        int u=q1.front();q1.pop();
        if(color[u]==0){
            color[u]=‘R‘;
            color[cf[u]]=‘B‘;
        }
        int sz=dag[u].size();
        for(int i=0;i<sz;++i){
            indeg[dag[u][i]]--;
            if(indeg[dag[u][i]]==0) q1.push(dag[u][i]);
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
    int n,m,u,v;
    char s1,s2;
    while(scanf("%d%d",&n,&m)==2) {
        if(n==0&&m==0) break;
        init();
        while(m--){
            scanf("%d%c %d%c",&u,&s1,&v,&s2);
            u=(s1==‘h‘) ?(2*u+1):(2*u);
            v=(s2==‘h‘) ?(2*v+1):(2*v);
//            cout<<"u="<<u<<" v="<<v<<endl;
//            cout<<"s1="<<s1<<" s2="<<s2<<endl;
            addedge(u,v^1);
            addedge(v,u^1);
        }
        addedge(0,1);
        if(!solveable(2*n)) puts("bad luck");
        else{
            solve(2*n);
            for(int i=1;i<n;++i){
                if(color[sccno[2*i]]==‘R‘) printf("%dh",i);
                else printf("%dw",i);
                if(i<n-1) printf(" ");
                else printf("\n");
            }
        }
    }
    return 0;
}

POJ3648.Wedding——2-sat输出任意解

标签:

原文地址:http://blog.csdn.net/u014141559/article/details/45193737

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!