POJ 3648 Wedding(2-SAT)
2015-07-31 10:50
357 查看
Description
有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:
1.每对夫妇不能坐在同一侧
2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。
如果存在一种可行的方案,输出与新娘同侧的人
Input
多组用例,每组用例第一行两个整数n和m表示n对夫妇以及m组通奸关系,之后m行每行一组通奸关系t1c1 t2c2,其中c1==’h’表示t1是丈夫,c1==’w’表示t1是妻子(结婚的一对新人看做第一组夫妇),以0 0结束输入
Output
对于每组用例,如果存在一组可行方案则输出与新娘同侧的人,如果不存在则输出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
Solution
2-SAT判断可行性,因为新郎必须坐在新娘对面,所以对新郎要特判,与新郎有奸情的人一定要坐在新娘一侧,构图时就构造一个~t->t即可,与新娘有奸情的人做哪一侧都行,对于其他人,如果t1与t2有奸情,则构造~t1->t2和~t2->t1,接下来只需用tarjan算法求强联通分量并判断是否有使得布尔公式值为真的一组布尔变量赋值即可,注意,因为要输出可行方案,所以要记录可行方案
Code
有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:
1.每对夫妇不能坐在同一侧
2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。
如果存在一种可行的方案,输出与新娘同侧的人
Input
多组用例,每组用例第一行两个整数n和m表示n对夫妇以及m组通奸关系,之后m行每行一组通奸关系t1c1 t2c2,其中c1==’h’表示t1是丈夫,c1==’w’表示t1是妻子(结婚的一对新人看做第一组夫妇),以0 0结束输入
Output
对于每组用例,如果存在一组可行方案则输出与新娘同侧的人,如果不存在则输出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
Solution
2-SAT判断可行性,因为新郎必须坐在新娘对面,所以对新郎要特判,与新郎有奸情的人一定要坐在新娘一侧,构图时就构造一个~t->t即可,与新娘有奸情的人做哪一侧都行,对于其他人,如果t1与t2有奸情,则构造~t1->t2和~t2->t1,接下来只需用tarjan算法求强联通分量并判断是否有使得布尔公式值为真的一组布尔变量赋值即可,注意,因为要输出可行方案,所以要记录可行方案
Code
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<stack> #include<vector> using namespace std; #define maxn 66 vector<int>g[maxn]; stack<int>st; int n,m,scc,index; int low[maxn],dfn[maxn],instack[maxn],fa[maxn]; int ans[maxn];//记录可行方案 void init()//初始化 { scc=index=0; while(!st.empty())st.pop(); for(int i=0;i<maxn;i++)g[i].clear(); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(low,0,sizeof(low)); memset(ans,0,sizeof(ans)); } void tarjan(int u)//求强联通分量 { dfn[u]=low[u]=++index; instack[u]=1; st.push(u); int v,size=g[u].size(); for(int i=0;i<size;i++) { v=g[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { scc++; do { v=st.top(); st.pop(); fa[v]=scc; instack[v]=0; }while(v!=u); } } bool check() { for(int i=0;i<2*n;i++)//求强联通分量 if(!dfn[i]) tarjan(i); for(int i=0;i<2*n;i+=2) { if(fa[i]==fa[i+1])//矛盾 return false; if(fa[i]<fa[i+1])//该对夫妇的妻子需要坐在新娘一侧 ans[i/2]=i; else//该对夫妇的丈夫需要坐在新娘一侧 ans[i/2]=i+1; } return true; } int main() { while(scanf("%d%d",&n,&m),n||m) { int t1,t2; char c1,c2; init(); for(int i=0;i<m;i++) { scanf("%d%c%d%c",&t1,&c1,&t2,&c2); //奇数项存丈夫,偶数项存妻子 if(c1=='h') t1=2*t1+1; else t1=2*t1; if(c2=='h') t2=2*t2+1; else t2=2*t2; if(t1==1)//t2与新郎有奸情,其必须坐在新娘一侧 g[t2^1].push_back(t2); else if(t2==1)//t1与新郎有奸情,其必须坐在新娘一侧 g[t1^1].push_back(t1); else if(t1==0||t2==0)////考虑新娘的奸情 {;} else//考虑其他人的奸情 { g[t2^1].push_back(t1); g[t1^1].push_back(t2); } } if(check())//存在可行方案 { int i; for(i=1;i<n-1;i++) { if(ans[i]==i*2) printf("%dw ",i); else printf("%dh ",i); } if(ans[i]==i*2) printf("%dw\n",i); else printf("%dh\n",i); } else//不存在可行方案 printf("bad luck\n"); } return 0; }
相关文章推荐
- poj3321 Apple Tree
- 使用git rebase合并多次commit
- 多校3- RGCDQ
- STM32学习笔记(一)-------GPIO口的操作
- 1.4-sar命令
- Java遍历读取文件目录结构
- 模拟windows消息框
- Canvas globalAlpha透明度属性(转)
- HTML DOM setInterval() 方法
- Android中Application类的用法
- 【HDOJ 5327】 Olympiad
- 配置Git自动补全功能
- BZOJ 2190 仪仗队
- unity3d ppsspp模拟器中的post processing shader在unity中使用
- 多校3- RGCDQ 分类: 比赛 HDU 2015-07-31 10:50 2人阅读 评论(0) 收藏
- 理解Windows内核模式与用户模式
- 升级Windows10正式版后触摸板手势有哪些变化?
- Reverse Words in a String
- dump data
- 经典makefile例子 http://blog.chinaunix.net/uid-25100840-id-2047826.html