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相关推荐

  1. [2-sat][topsort输出解] POJ 3648 Wedding

    2-sat 基本是有三类题型,一种只判定解是否存在,一种判定+二分答案求最佳,一种判定解并输出其中一组解. Wedding 这题是典型的第三种类型. ps. 最近太忙了,这题是前天A的,暂时先要把 2 ...

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

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

  3. (转)2-sat 专题

    [2-sat]专题- 2-sat是一个逻辑性很强的算法,但是其套路比较固定,所以不是很热,题目很少,但也不乏AC后让人大呼爽快的好题,下面放出两篇极品论文还有几道题目的题解以供交流-- 2-sat学习 ...

  4. 【转载】图论 500题——主要为hdu/poj/zoj

    转自--http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...

  5. 【HDOJ图论题集】【转】

    1 =============================以下是最小生成树+并查集====================================== 2 [HDU] 3 1213 How ...

  6. 一系列图论问题[转]

    =============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...

  7. 图论练习题(存起来练)

    =============================以下是最小生成树+并查集======================================  [HDU]  1213 How Man ...

  8. [kuangbin]各种各样的题单

    [kuangbin]各种各样的题单 专题1 简单搜索 POJ 1321 POJ 2251 POJ 3278 POJ 3279 POJ 1426 POJ 3126 POJ 3087 POJ 3414 F ...

  9. linux时间为什么没有北京,linux修改时区为中国时区(北京)

    [linux]linux下运行java程序 参考了http://www.cnblogs.com/howard-queen/archive/2012/01/30/2331795.html 第一步:用vi ...

最新文章

  1. js 正则 显示千分号 支持整数和小数
  2. netflow流量分析工具 linux,Centos5/Linux安装Nfdump和Nfsen图形界面分析netflow数据
  3. Spring之AOP实现
  4. HDFS dfsclient写文件过程 源码分析
  5. MySQL数据库学习笔记(九)----JDBC的ResultSet接口(查询操作)、PreparedStatement接口重构增删改查(含SQL注入的解释)...
  6. Java中的IO流(六)
  7. okhttp请求php接口,安卓:okhttp请求,获取返回数据
  8. 周日慕田峪生鱼片之旅,失败的第一次出台
  9. 谈谈OAB离线地址簿无法更新问题?(服务器是Exchange 2007和Exchange 2010)
  10. Word插入插图清单目录、附表清单目录
  11. 嵌入式开发与单片机开发有什么区别
  12. 一文读懂程序化交易、算法交易、量化交易、高频交易、 统计套利的区别
  13. 计算机病毒实验教程pdf,计算机病毒实验报告-1
  14. Latex 环境配置(TexLive + Texstudio)
  15. C++中cin,cin.get()和cin.getline()的区别
  16. Scrapy爬虫框架入门(一)——阳光政务平台
  17. 记录一下落地网关soul(shenyu)过程中的一些实践
  18. c语言课设ktv点歌系统1,C语言ktv点歌系统
  19. ID卡线圈和IC卡线圈的区别
  20. 【办公软件有哪些】万彩办公大师教程丨PDF页面编辑

热门文章

  1. 李林APUE之进程的封装
  2. 【插件】史上最强编辑器通用ctags插件OpenCTags使用指南v1.2--开发者必备
  3. SQL Server之视图基础知识
  4. mongodb与mysql命令对比 (前人笔记+自己添加)
  5. 在一测试环境下的RAC出错解决
  6. Android 自定义属性时TypedArray的使用
  7. Windows常用命令行命令
  8. android开源许可证
  9. 数据库性能优化—分库分表
  10. 创建型模式—原型模式