题意:有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 输出解决方案)的更多相关文章

  1. POJ 3648 Wedding(2-SAT的模型运用+DFS | Tarjan)

    Wedding Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10427   Accepted: 3170   Specia ...

  2. poj 3648 Wedding 2-SAT问题入门题目

    Description Up to thirty couples will attend a wedding feast, at which they will be seated on either ...

  3. POJ 3648 Wedding (2-SAT,经典)

    题意:新郎和新娘结婚,来了n-1对夫妻,这些夫妻包括新郎之间有通奸关系(包括男女,男男,女女),我们的目地是为了满足新娘,新娘对面不能坐着一对夫妻,也不能坐着有任何通奸关系的人,另外新郎一定要坐新娘对 ...

  4. POJ 3648 Wedding

    2-SAT,直接选择新娘一侧的比较难做,所以处理的时候选择新郎一侧的,最后反着输出就可以. A和B通奸的话,就建边 A->B'以及B->A’,表示 A在新郎一侧的话,B一定不在:B在新郎一 ...

  5. POJ.3648.Wedding(2-SAT)

    题目链接 题意看这吧..https://www.cnblogs.com/wenruo/p/5885948.html \(Solution\) 每对夫妇只能有一个坐在新娘这一边,这正符合2-SAT初始状 ...

  6. poj 3648 Wedding【2-SAT+tarjan+拓扑】

    看错题*n,注意是输出新娘这边的-- 按2-SAT规则连互斥的边,然后注意连一条(1,1+n)表示新娘必选 然后输出color[belong[i]]==color[belong[1+n(新娘)]]的点 ...

  7. Wedding (poj 3648 2-SAT 输出随意一组解)

    Language: Default Wedding Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9004   Accept ...

  8. 【POJ】3648 Wedding

    http://poj.org/problem?id=3648 题意:n对人(编号0-n-1,'w'表示第一个人,'h'表示第二个人),每对两个,人坐在桌子两侧.满足:1.每对人中的两个人不能坐在同一侧 ...

  9. poj 3648 2-SAT建图+topsort输出结果

    其实2-SAT类型题目的类型比较明确,基本模型差不多是对于n组对称的点,通过给出的限制条件建图连边,然后通过缩点和判断冲突来解决问题.要注意的是在topsort输出结果的时候,缩点后建图需要反向连边, ...

随机推荐

  1. 打开cmd闪退

    我们在使用电脑过程中一般会很少用到cmd命令,CMD命令窗口在一些特殊情况时我们会用到,如PING下看网络通不通.在CMD窗口里运行命令如磁盘格式转换,但是有些朋友遇到了这样的问题,在开始运行输入CM ...

  2. C语言字符串的输入输出

    字符串的输出 在C语言中,输出字符串的函数有两个: puts():直接输出字符串,并且只能输出字符串. printf():通过格式控制符 %s 输出字符串.除了字符串,printf() 还能输出其他类 ...

  3. HTML-网页常见错误

    400 请求出错  由于语法格式有误,服务器无法理解此请求.不作修改,客户程序就无法重复此请求.  HTTP 错误 401  401.1 未授权:登录失败  此错误表明传输给服务器的证书与登录服务器所 ...

  4. Android之dip、dp、px、sp和屏幕密度

    1. dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这 这个,不依 ...

  5. Win7下搭建安卓android开发环境

    本文出自 “孤狼” 博客,请务必保留此出处http://332374363.blog.51cto.com/5262696/1310882 另外,在搭建android开发环境时,还参考了http://w ...

  6. Python--Get and Post

    #python3 get and post 简单封装 from urllib import request, parse import json def RequestMethod(methodR, ...

  7. 第九课——redis集群

    第九课时作业 静哥 by 2016.4.18~2016.4.25 1.节点 (1)节点概念:一个节点就是redis集群里的一台redis服务器.一个redis集群是由多个节点(node)组成,最初每个 ...

  8. 演示一个简单的Redis队列

    0.Windows Service版下载 https://github.com/rgl/redis/downloads 1.新建一个Console项目 打开Nuget控制台,执行以下命令 Instal ...

  9. Python 之 UUID

    UUID是根据MAC以及当前时间等创建的不重复的随机字符串 import uuid # Generate a UUID from a host ID, sequence number, and the ...

  10. Django 框架之 URL

    URL配置就像Django所支撑网站的目录.它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表. # 示例: urlpatterns = [ path(route, view, kwa ...