POJ - 3648 Wedding (2-SAT 输出解决方案)
题意:有N-1对夫妇和1对新郎新娘要出席婚礼,这N对人要坐在走廊两侧。要求每对夫妇要坐在不同侧。有M对人有通奸关系,对于这一对人,不能同时坐在新娘对面(新娘新郎也可能和别人有通奸关系)。求如何避免冲突安排每对人。
分析:相当于选择N个坐在新娘对面且不会冲突的人。根据给定的M条关系建图,若a与b有关系,则选a坐对面则必定选b的伴侣坐对面;且选b坐对面则必定选a的伴侣坐对面。最后要加一条(0,1)的有向边(保证新郎一定会被选到另一侧)。
建图后跑Tarjan,若有一对夫妻处在强连通分量中,则无解;否则强连通缩点后根据关系染色,输出每对夫妻中与新娘同色的人。
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn =1e3+5;
struct Edge{
    int v,next;
}edges[maxn<<2],E[maxn<<2];
int head[maxn],tot;
int H[maxn],tt;
stack<int> S;
int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt,ind[maxn],col[maxn];
void init()
{
    tt = tot = dfn = scc_cnt=0;
    memset(H,-1,sizeof(H));
    memset(col,0,sizeof(col));
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    memset(head,-1,sizeof(head));
    memset(ind,0,sizeof(ind));
}
void AddEdge(int u,int v)   {
    edges[tot] = (Edge){v,head[u]};
    head[u] = tot++;
}
void nAddEdge(int u,int v){
    E[tt] = (Edge){v,H[u]};
    H[u] = tt++;
}
void Tarjan(int u)
{
    int v;
    pre[u]=low[u]=++dfn;
    S.push(u);
    for(int i=head[u];~i;i=edges[i].next){
        v= edges[i].v;
        if(!pre[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v]){
            low[u]=min(low[u],pre[v]);
        }
    }
    if(pre[u]==low[u]){
        int x;
        ++scc_cnt;
        for(;;){
            x = S.top();S.pop();
            sccno[x]=scc_cnt;
            if(x==u)break;
        }
    }
}
int n,m;
int bad[maxn];
void solve()
{
    int all = 2*n,a,b;
    for(int u = 0;u<all;u+=2){
        a = sccno[u] ,b = sccno[u+1];
        if(a == b){
            printf("bad luck\n");
            return;
        }
        bad[a] = b;
        bad[b] = a;
    }
    //缩点
    for(int u=0;u<all;u++){
        a = sccno[u];
        for(int i =head[u];~i;i=edges[i].next){
            int v = edges[i].v;
            b = sccno[v];
            if(a!=b){
                ind[b]++;
                nAddEdge(a,b);          //逆拓扑排序
            }
        }
    }
    //拓扑排序染色
    queue<int> Q;
    for(int u=1;u<=scc_cnt;++u){
        if(!ind[u]) Q.push(u);
    }
    while(!Q.empty()){
        int u = Q.front(); Q.pop();
        if(!col[u]){
            col[u] = 1;
            col[bad[u]] = 2;
        }
        for(int i=H[u];~i;i=E[i].next){
            int v= E[i].v;
            ind[v]--;
            if(!ind[v]){
                Q.push(v);
            }
        }
    }
    for(int i=2;i<all;i+=2){
        if(i!=2) printf(" ");
        if(col[sccno[i]]==col[sccno[0]]) printf("%dw",i/2);
        else printf("%dh",i/2);
    }
    puts("");
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int u,v,tmp;
    char c1,c2;
    while(scanf("%d %d",&n,&m)==2){
        if(!n &&!m) break;
        init();
        int id1,id2,x1,y1;
        for(int i = 1;i<=m;++i){
            scanf("%d%c %d%c",&id1,&c1,&id2,&c2);
            if(c1=='h') x1 = 2*id1+1;
            else x1 = 2*id1;
            if(c2=='h') y1 = 2*id2+1;
            else  y1 = 2*id2;
            //如果x与y有**关系,则有关系:选x必选y' 且 选y必选x'
            AddEdge(x1,y1^1);
            AddEdge(y1,x1^1);
        }
        AddEdge(0,1);       //这样如果选了新娘就会判断无解,选出来的组合一定包含新郎
        int all = 2*n;
        for(int i=0;i<all;++i){
            if(!pre[i]){
                Tarjan(i);
            }
        }
        solve();
    }
    return 0;
}
POJ - 3648 Wedding (2-SAT 输出解决方案)的更多相关文章
- POJ 3648 Wedding(2-SAT的模型运用+DFS | Tarjan)
		Wedding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10427 Accepted: 3170 Specia ... 
- poj 3648 Wedding 2-SAT问题入门题目
		Description Up to thirty couples will attend a wedding feast, at which they will be seated on either ... 
- POJ 3648 Wedding (2-SAT,经典)
		题意:新郎和新娘结婚,来了n-1对夫妻,这些夫妻包括新郎之间有通奸关系(包括男女,男男,女女),我们的目地是为了满足新娘,新娘对面不能坐着一对夫妻,也不能坐着有任何通奸关系的人,另外新郎一定要坐新娘对 ... 
- POJ 3648 Wedding
		2-SAT,直接选择新娘一侧的比较难做,所以处理的时候选择新郎一侧的,最后反着输出就可以. A和B通奸的话,就建边 A->B'以及B->A’,表示 A在新郎一侧的话,B一定不在:B在新郎一 ... 
- POJ.3648.Wedding(2-SAT)
		题目链接 题意看这吧..https://www.cnblogs.com/wenruo/p/5885948.html \(Solution\) 每对夫妇只能有一个坐在新娘这一边,这正符合2-SAT初始状 ... 
- poj 3648 Wedding【2-SAT+tarjan+拓扑】
		看错题*n,注意是输出新娘这边的-- 按2-SAT规则连互斥的边,然后注意连一条(1,1+n)表示新娘必选 然后输出color[belong[i]]==color[belong[1+n(新娘)]]的点 ... 
- Wedding (poj 3648 2-SAT 输出随意一组解)
		Language: Default Wedding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9004 Accept ... 
- 【POJ】3648 Wedding
		http://poj.org/problem?id=3648 题意:n对人(编号0-n-1,'w'表示第一个人,'h'表示第二个人),每对两个,人坐在桌子两侧.满足:1.每对人中的两个人不能坐在同一侧 ... 
- poj 3648 2-SAT建图+topsort输出结果
		其实2-SAT类型题目的类型比较明确,基本模型差不多是对于n组对称的点,通过给出的限制条件建图连边,然后通过缩点和判断冲突来解决问题.要注意的是在topsort输出结果的时候,缩点后建图需要反向连边, ... 
随机推荐
- WPF - 绑定及惯用法(一)
			写在前面:这仍然是一些没有经过严格审阅的文字.虽然我的确执行了初稿.复稿以及审阅等一系列用以保证文章质量的方法,但是仍然担心其中是否有错误.希望您能帮助指出,以在下一次我在版本更新时进行修正.所有的错 ... 
- 数据仓库与BI面试常见题目
			一. 数据库 1. Oracle数据库,视图与表的区别?普通视图与物化视图的区别?物化视图的作用?materialized view 答:a:视图是虚拟表,提高了表的安全性,视图没有实际物理空间,而表 ... 
- (转)Python中的random模块
			Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ... 
- iOS:友盟SDK第三方登录 分享及友盟统计的使用
			本文转载至 http://www.it165.net/pro/html/201503/37101.html Tag标签:第三方 01.#import "UMSocial.h" ... 
- POI读写大数据量EXCEL
			另一篇文章http://www.cnblogs.com/tootwo2/p/8120053.html里面有xml的一些解释. 大数据量的excel一般都是.xlsx格式的,网上使用POI读写的例子比较 ... 
- JZOJ.5288【NOIP2017模拟8.17】球场大佬
			Description 每天下午,古猴都会去打羽毛球.但是古猴实在是太强了,他必须要到一些比较强的场去打.但是每个羽毛球场都有许多的人排着队,每次都只能上四个人,每个人都有自己的能力值,然 ... 
- python练习题集合-2
			author:headsen chen date:2018-06-01 15:39:26 习题17,文件的更多操作 [root@localhost py]# echo > cc.txt [ro ... 
- java的Enumeration转list
			java的Enumeration转list Enumeration<String> attrs = getAttrNames();// while(attrs.hasMoreElement ... 
- oracle导入sql文件
			oracle导入sql文件: 1.进入到sql文件目录下,登录需要导入文件的用户 打开cmd,输入以下命令,进入oracle, sqlplus username/password username:需 ... 
- Linux文件操作相关命令
			1.创建文件夹: [root@izuf6ih01h8fzeziddwkfdz sm]# mkdir a 创建一个名为a的文件夹 2.创建文件: [root@izuf6ih01h8fzeziddwkfd ... 
