POJ 3648 Wedding
POJ_3648
首先要注意两个和算法无关地方:①题目的输入数据存在诸如“2w5h”的情况,因此直接用scanf(“%s%s”,b1,b2)去读取数据会WA。②题目中的意思是找出一组能和新娘坐在一起的人,而题目中描述的对于人的限制都是指的对面的,因此我们要先利用已知把对面的人的序列构造出来,再输出对应的新娘这边的人的序列即可。
这是我的第一个2-SAT的题目,做完一题相当于复习了好多图论的知识……总的来说,这类问题一般的步骤是这个样子的:
①根据已知条件建图。比如这一题,已知的条件是x和y不能同时坐在对面(注意,与不能同时坐在一起是不同的),那么我们就要连两条边,x->~y,y->~x,至于为什么这么建图,主要是从意义上考虑的,x和y不能同时坐在对面,也就是说如果坐了x,那么对面就只能做~y,反过来也是一样的,所以x->~y与~y->x不是等价的。如果我们设新娘是0,新郎是1的话,同时需要连一条0->1的边,表示对面只能坐新郎,因为如果0坐在对面,那么1也要坐在对面,显然不符合逻辑。
②用tarjan算法(当然别的算法也可以,只不过我只会tarjan)求强连通分量。至于为什么有这一步,可以参考PPT《由对称性解2-SAT问题》。
③判断每个集合中的两个元素是否在同一个强连通分量中。如果存在一个集合中的两个元素在同一个强连通分量中,则无解,否则一定有解(至于为什么一定有解,可以参考PPT《由对称性解2-SAT问题》)。
④依原来的有向边,将缩后的点构造成反向图并进行拓扑排序(便于后续的处理)。
⑤删点并记录方案。这个过程需要一个数组del[]表示缩后的点是否被删去,然后依次遍历每个强连通分量,如果del[]不为1,则把强连通分量里的值全部取出,在取出的x的同时,删除~x所在的强连通分量以及该强连通分量的所有直接或间接的子节点。这样的做的目的可以这么来理解,如果我们选择了x,那么就不能选~x,所以凡是选了y就必须选~x的y都要被删去,又因为我们建的是反图,所以要删掉所有~x所在的强连通分量以及该强连通分量的所有直接或间接的子节点。
⑥打印结果。
#include<stdio.h>#include<string.h>#include<stdlib.h>int n, m, N, G[1010][1010];int col , a[1010][1010], num[1010], color[1010];int g[1010][1010], dfn[1010], low[1010];int s[1010], top, time, ins[1010];int topo[1010], t, del[1010], vis[1010];int ans[1010], res;int cmp(const void *_p,const void *_q){int *p=(int *)_p;int *q=(int *)_q;return *p-*q;}int init(){int i, j, k, n1, n2;char b1,b2; scanf("%d%d", &n, &m);if(!n&&!m)return 0; N = 2 * n; memset(G, 0, sizeof(G));for(i = 0; i < m; i ++) { scanf("%d%c%d%c", &n1, &b1, &n2, &b2); n1 = n1 * 2 + (b1 == 'h'); n2 = n2 * 2 + (b2 == 'h'); G[n1][n2 ^ 1] = 1; G[n2][n1 ^ 1] = 1; } G[0][1] = 1;return 1;}void tarjan(int u){int i, j, v; dfn[u] = low[u] = ++time;for(v = 0; v < N; v ++)if(G[u][v]) {if(!dfn[v]) { s[top ++] = v; ins[v] = 1; tarjan(v);if(low[v] < low[u]) low[u] = low[v]; }else if(ins[v] && dfn[v] < low[u]) low[u] = dfn[v]; }if(low[u] == dfn[u]) {for(i = 0, s[top] = -1; s[top] != u; i++) { top --; a[col][i] = s[top]; color[s[top]] = col; ins[s[top]] = 0; } num[col] = i; col ++; }}int judge(){int i;for(i = 0;i < N; i ++)if(color[i] == color[i ^ 1])return 0;return 1;}int dfs(int u){int i, j, v; vis[u] = -1;for(v = 0; v < col; v ++)if(g[u][v]) {if(vis[v] == -1)return 0;if(!vis[v] && !dfs(v))return 0; } vis[u] = 1; topo[-- t] = u;return 1;}int toposort(){int i, j, k; t = col; memset(vis, 0, sizeof(vis));for(i = 0; i < col; i ++)if(!vis[i] && !dfs(i))return 0;return 1;}void dfsdel(int u){int v; del[u] = 1;for(v = 0; v < col; v ++)if(g[u][v] && !del[v]) dfsdel(v);}void search(int i){int j, p; del[i] = 1;for(j = 0; j < num[i]; j ++) { p = a[i][j]; ans[res ++] = p;if(!del[color[p ^ 1]]) dfsdel(color[p ^ 1]); }}int com(){int i, j, k, p, ok; top = time = col = 0; memset(ins, 0, sizeof(ins)); memset(dfn, 0, sizeof(dfn));for(i = 0; i < N; i ++)if(! dfn[i]) { s[top ++] = i; ins[i] = 1; tarjan(i); }if(!judge())return 0; memset(g, 0, sizeof(g));for(i=0;i<N;i++)for(j=0;j<N;j++)if(G[i][j] && color[i] != color[j]) g[color[j]][color[i]] = 1;if(!toposort())return 0; memset(del , 0, sizeof(del)); res = 0;for(i = 0; i < col; i ++)if(!del[topo[i]]) search(topo[i]);if(res != n)return 0;return 1;}void printpath(){int i, j, tt; tt = 0; qsort(ans, res, sizeof(ans[0]), cmp);for(i = 1; i < res; i ++) {if(tt ++) printf(" "); printf("%d%c", ans[i] / 2, ans[i] % 2 == 0 ? 'h' : 'w'); } printf("\n");}int main(){while(init()) {if(com()) printpath();else printf("bad luck\n"); }return 0; }
转载于:https://www.cnblogs.com/staginner/archive/2011/10/02/2198263.html
POJ 3648 Wedding相关推荐
- [2-sat][topsort输出解] POJ 3648 Wedding
2-sat 基本是有三类题型,一种只判定解是否存在,一种判定+二分答案求最佳,一种判定解并输出其中一组解. Wedding 这题是典型的第三种类型. ps. 最近太忙了,这题是前天A的,暂时先要把 2 ...
- POJ.3648.Wedding(2-SAT)
题目链接 题意看这吧..https://www.cnblogs.com/wenruo/p/5885948.html \(Solution\) 每对夫妇只能有一个坐在新娘这一边,这正符合2-SAT初始状 ...
- (转)2-sat 专题
[2-sat]专题- 2-sat是一个逻辑性很强的算法,但是其套路比较固定,所以不是很热,题目很少,但也不乏AC后让人大呼爽快的好题,下面放出两篇极品论文还有几道题目的题解以供交流-- 2-sat学习 ...
- 【转载】图论 500题——主要为hdu/poj/zoj
转自--http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...
- 【HDOJ图论题集】【转】
1 =============================以下是最小生成树+并查集====================================== 2 [HDU] 3 1213 How ...
- 一系列图论问题[转]
=============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...
- 图论练习题(存起来练)
=============================以下是最小生成树+并查集====================================== [HDU] 1213 How Man ...
- [kuangbin]各种各样的题单
[kuangbin]各种各样的题单 专题1 简单搜索 POJ 1321 POJ 2251 POJ 3278 POJ 3279 POJ 1426 POJ 3126 POJ 3087 POJ 3414 F ...
- linux时间为什么没有北京,linux修改时区为中国时区(北京)
[linux]linux下运行java程序 参考了http://www.cnblogs.com/howard-queen/archive/2012/01/30/2331795.html 第一步:用vi ...
最新文章
- js 正则 显示千分号 支持整数和小数
- netflow流量分析工具 linux,Centos5/Linux安装Nfdump和Nfsen图形界面分析netflow数据
- Spring之AOP实现
- HDFS dfsclient写文件过程 源码分析
- MySQL数据库学习笔记(九)----JDBC的ResultSet接口(查询操作)、PreparedStatement接口重构增删改查(含SQL注入的解释)...
- Java中的IO流(六)
- okhttp请求php接口,安卓:okhttp请求,获取返回数据
- 周日慕田峪生鱼片之旅,失败的第一次出台
- 谈谈OAB离线地址簿无法更新问题?(服务器是Exchange 2007和Exchange 2010)
- Word插入插图清单目录、附表清单目录
- 嵌入式开发与单片机开发有什么区别
- 一文读懂程序化交易、算法交易、量化交易、高频交易、 统计套利的区别
- 计算机病毒实验教程pdf,计算机病毒实验报告-1
- Latex 环境配置(TexLive + Texstudio)
- C++中cin,cin.get()和cin.getline()的区别
- Scrapy爬虫框架入门(一)——阳光政务平台
- 记录一下落地网关soul(shenyu)过程中的一些实践
- c语言课设ktv点歌系统1,C语言ktv点歌系统
- ID卡线圈和IC卡线圈的区别
- 【办公软件有哪些】万彩办公大师教程丨PDF页面编辑