poj 3648 Wedding 【2-sat 经典建图 输出一组可行解 好题】 【tarjan求SCC + 缩点 + 拓扑排序 + 染色】
来源:互联网 发布:剪切合并音乐软件 编辑:程序博客网 时间:2024/05/19 13:20
Description
Up to thirty couples will attend a wedding feast, at which they will be seated on either side of a long table. The bride and groom sit at one end, opposite each other, and the bride wears an elaborate headdress that keeps her from seeing people on the same side as her. It is considered bad luck to have a husband and wife seated on the same side of the table. Additionally, there are several pairs of people conducting adulterous relationships (both different-sex and same-sex relationships are possible), and it is bad luck for the bride to see both members of such a pair. Your job is to arrange people at the table so as to avoid any bad luck.
Input
The input consists of a number of test cases, followed by a line containing 0 0. Each test case gives n, the number of couples, followed by the number of adulterous pairs, followed by the pairs, in the form "4h 2w" (husband from couple 4, wife from couple 2), or "10w 4w", or "3h 1h". Couples are numbered from 0 to n - 1 with the bride and groom being 0w and 0h.
Output
For each case, output a single line containing a list of the people that should be seated on the same side as the bride. If there are several solutions, any one will do. If there is no solution, output a line containing "bad luck".
Sample Input
10 63h 7h5w 3w7h 6w8w 3w7h 3w2w 5h0 0
Sample Output
1h 2h 3w 4h 5h 6h 7h 8h 9h
题意:很多对夫妇参加一对新人的婚礼。分别做在长桌子的两侧。新郎、新娘分别坐两侧,新娘只能看到她对面的人。新娘不想看到她对面有夫妇。
而且有一些人是有通奸关系的(男男,男女、女女都可能有,而且新郎也可能和别人有通奸关系),新娘不想看到有通奸关系的一对人坐在她对面。
转化问题:我们需要选出包括新郎在内的一半人坐在新娘对面去,选出来的人不能有夫妇,不能有通奸关系的一对人。可以选择编号第i对夫妇中妻子为
2*i,丈夫为2*i+1。那么则有新郎为1,新娘为0;
建图:对于 a op1 b op2
一:a男 b男
1,addEdge(2*a + 1, 2*b);//选了a男到新娘对面 也必选b男妻子
2,addEdge(2*b + 1, 2*a);//选了b男到新娘对面 也必选a男妻子
二:a男 b女
1,addEdge(2*a + 1, 2*b + 1);//选了a男到新娘对面 也必选b女丈夫
2,addEdge(2*b, 2*a);//选了b女到新娘对面 也必选a男妻子
1,addEdge(2*a, 2*b);//选了a女到新娘对面 也必选b男妻子
2,addEdge(2*b + 1, 2*a + 1);//选了b男到新娘对面 也必选a女丈夫
四:a女 b女
1,addEdge(2*a, 2*b + 1);//选了a女到新娘对面 也必选b女丈夫
2,addEdge(2*b, 2*a + 1);//选了b女到新娘对面 也必选a女丈夫
最最重要的是我们必需选择新郎,加一条0->1的边,表示必选1。看代码注释
注意的是输出的时候是输出和新娘坐同一边的人。即反过来输出就可以了;
#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <stack>#include <algorithm>#define MAXN 100#define MAXM 100000#define INF 10000000#define eps 1e-5using namespace std;struct Edge{int from, to, next;}edge[MAXM];//原图int head[MAXN], edgenum; vector<int> G[MAXN];//缩点后新图 int in[MAXN];//新图SCC的入度 int low[MAXN], dfn[MAXN];int dfs_clock;int sccno[MAXN], scc_cnt;stack<int> S;bool Instack[MAXN];int N, M;int color[MAXN];//染色 int fp[MAXN];//建立对应SCC编号的映射 void init(){edgenum = 0;memset(head, -1, sizeof(head)); }void addEdge(int u, int v){Edge E = {u, v, head[u]};edge[edgenum] = E;head[u] = edgenum++;} void getMap()//选择N个人到新娘对面 {addEdge(0, 1);//表示必选新郎 因为选择新娘必选新郎 -> 矛盾 int a, b;char op1, op2;while(M--){getchar();scanf("%d%c %d%c", &a, &op1, &b, &op2);if(op1 == 'h' && op2 == 'h')//a男 b男 {addEdge(2*a + 1, 2*b);//选了a男到新娘对面 也必选b男妻子 addEdge(2*b + 1, 2*a);//选了b男到新娘对面 也必选a男妻子 } else if(op1 == 'h' && op2 == 'w')//a男 b女 {addEdge(2*a + 1, 2*b + 1);//选了a男到新娘对面 也必选b女丈夫 addEdge(2*b, 2*a);//选了b女到新娘对面 也必选a男妻子 }else if(op1 == 'w' && op2 == 'h')//a女 b男 {addEdge(2*a, 2*b);//选了a女到新娘对面 也必选b男妻子 addEdge(2*b + 1, 2*a + 1);//选了b男到新娘对面 也必选a女丈夫 }else//a女 b女 {addEdge(2*a, 2*b + 1);//选了a女到新娘对面 也必选b女丈夫 addEdge(2*b, 2*a + 1);//选了b女到新娘对面 也必选a女丈夫 }}} void tarjan(int u, int fa){int v;low[u] = dfn[u] = ++dfs_clock;S.push(u);Instack[u] = true;for(int i = head[u]; i != -1; i = edge[i].next){v = edge[i].to;if(!dfn[v]){tarjan(v, u);low[u] = min(low[u], low[v]);}else if(Instack[v])low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]){scc_cnt++;for(;;){v = S.top(); S.pop();Instack[v] = false;sccno[v] = scc_cnt;if(v == u) break;}}}void find_cut(int l, int r){memset(low, 0, sizeof(low));memset(dfn, 0, sizeof(dfn));memset(sccno, 0, sizeof(sccno));memset(Instack, false, sizeof(Instack));dfs_clock = scc_cnt = 0;for(int i = l; i <= r; i++)if(!dfn[i]) tarjan(i, -1);}void suodian(){for(int i = 1; i <= scc_cnt; i++) G[i].clear(), in[i] = 0;for(int i = 0; i < edgenum; i++){int u = sccno[edge[i].from];int v = sccno[edge[i].to];if(u != v)G[v].push_back(u), in[u]++; } }void toposort(){queue<int> Q;memset(color, 0, sizeof(color));for(int i = 1; i <= scc_cnt; i++) if(in[i] == 0) Q.push(i);while(!Q.empty()){int u = Q.front();Q.pop();if(color[u] == 0){color[u] = 1;color[fp[u]] = 2;}for(int i = 0; i < G[u].size(); i++){int v = G[u][i];if(--in[v] == 0)//入度减一 Q.push(v);}}}void solve(){memset(fp, 0, sizeof(fp));for(int i = 0; i < N; i++){if(sccno[2*i] == sccno[2*i + 1]){printf("bad luck\n");return ;}else{fp[sccno[2*i]] = sccno[2*i + 1];fp[sccno[2*i + 1]] = sccno[2*i];}}suodian();//缩点 toposort();//拓扑排序 + 染色 for(int i = 1; i < N; i++){if(color[sccno[2*i]] == 1)//选了妻子去对面 printf("%dh ", i);//输出对应丈夫 elseprintf("%dw ", i);//同上 }printf("\n");}int main(){while(scanf("%d%d", &N, &M), N||M){init();getMap();find_cut(1, 2*N-1);solve(); }return 0;}
- poj 3648 Wedding 【2-sat 经典建图 输出一组可行解 好题】 【tarjan求SCC + 缩点 + 拓扑排序 + 染色】
- poj 3648 Wedding+2-sat+SCC+缩点+拓扑排序
- Poj 3648 Wedding【2-Sat--------Tarjan强连通+缩点染色+拓扑排序】
- poj 3648 Wedding(2-sat--拓扑排序输出可行解)
- poj 3683 Priest John's Busiest Day 【2-sat 经典建图输出一组解】【有向图tarjan + 反向拓扑 + 染色】
- 2-sat 输出任意一组可行解&拓扑排序+缩点 poj3683
- POJ 3648 Wedding (2-SAT+输出可行解)
- POJ 3648 Wedding (Tarjan + 缩点 + 拓扑排序)
- poj 3648 wedding(2-sat 拓扑排序输出方案)
- Wedding (poj 3648 2-SAT 输出任意一组解)
- POJ 3648 Wedding 2-sat输出一组解
- POJ 3648 Wedding(2-SAT输出一组解)
- LightOJ 1251 Forming the Council【2-Sat+逆向拓扑排序输出可行解】好题!
- POJ 3648 Wedding(2-SAT 拓扑排序输出任意一种解决方案)
- poj 3683(2-sat+输出一组可行解)
- poj 3683 2-sat问题,输出任意一组可行解
- poj 2762 Going from u to v or from v to u? 【判断图是否为弱连通】 【tarjan求SCC + 缩点 + 拓扑排序】
- [POJ 3683]Priest John's Busiest Day(2-SAT+拓扑排序输出可行解)
- 理解二级指针
- java web项目中将数据库从SQL Server转为Access出现的常见错误
- ora-01036: 非法的变量名/编号
- windows7环境下theano安装
- BC一周年A
- poj 3648 Wedding 【2-sat 经典建图 输出一组可行解 好题】 【tarjan求SCC + 缩点 + 拓扑排序 + 染色】
- C++学习,总结一
- laravel实用笔记
- iOS动画之大雪纷飞
- HDU 2178 猜数字(二分)
- FS_S5PC100平台上Linux Camera驱动开发详解(一)
- 图形设计
- linux性能分析命令-扫盲贴
- linux程序设计——多客户(第十五章)