bzoj3495 PA2010 Riddle(2-SAT 前缀优化建边)
来源:互联网 发布:淘宝网跑步机 编辑:程序博客网 时间:2024/05/29 02:18
bzoj3495 PA2010 Riddle
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3495
题意:
k个国家,几个城市,m条边。
要求每个国家有且仅有一个首都,每条边两端的城市至少要有一个首都。
判断是否有解, 有解输出“TAK”,无解输出”NIE”。
数据范围
1 < = k, N ,M , < =1000000
题解:
传统建边O(n^2),舍弃,考虑前缀优化。
解法是前缀一个点拆成四个点,分别表示:这个城市是首都/这个城市不是首都、这个城市所属国家中到这个城市的前缀包含首都\不包含首都。
令城市点为i,对应前缀点pre[i],上面加个 ` 表示反点。这里的建边都表示同时建了反变(
那么
跑2-SAT即可。
这道题让我想到了UOJ 210
很容易想到前后缀建边优化,可以从这类题中归纳出一个建边方向的问题 。
UOJ210的前后缀可以直接与单独的点相关,因为前缀/后缀假话点可以直接指向这个人是犯人,而这个人是犯人却不能直接指向某条供词是假的。
此题,前后缀城市有首都 也不能对应到某个城市是不是首都 ,因此是点的真连向前缀的真。
但是网上很多题解说只需要前缀即可,为什么?
实际上,只建前缀点并不能保证有且只有一个首都,可能合法方案是一个国家根本没有首都。所有的前缀都是假的。
那么建立后缀节点呢?前缀全假总能对应后缀为真了吧。
即使建立了后缀点,那么我们确实杜绝了一个国家的所有前后缀都不是首都的情况,
但这个前后缀是首都, 并不能指向某个城市是首都。
只有前后缀不是首都,才能指向某个城市不是首都。
还是有可能一个国家全部不是首都。
所以建不建后缀的效果相同。保证的都是<=1却没保证有。(因此UOJ210也可以只前缀优化)
那么为什么这样可行呢?
假设我们构造出一组”合法”方案,但其中存在某个国家没有首都,所有前缀都为假。
观察原建边方式可知,由于”两端的城市至少要有一个首都” ,可以都是首都,
如果我们定义是首都/前缀包含首都为真,不是首都/前缀不包含首都为假:
发现城市的真只连向对应前缀的真,和对应前缀前一个前缀的假,
而对应前缀的真只会连向后一个城市的假,和后一个前缀的真,
以此类推,发现如果任意把一个城市改为真,影响的只会是之后的前缀变为了真,而这些前缀并不能指向某个城市的真。
(剩下的本来就是假的现在还是假的)
于是对于没有首都的国家,任意改变一个城市为首都是可行的。
于是对于这种建图,如果判定有解,总能找出一组合法解,究其原因就是因为“每条边两端的城市至少要有一个首都”这个条件。
代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int N=1000100;int n,m,k,id[N],idc=1,pl[4*N],cnt=0,stack[4*N],top=0,inc=0,dfn[4*N],low[4*N];int head[4*N],nxt[16*N],to[16*N],num=1;bool ins[4*N];void build(int u,int v){ num++; to[num]=v; nxt[num]=head[u]; head[u]=num;}void add(int u,int v){ build(u,v); build(v^1,u^1);}void dfs(int u){ inc++; dfn[u]=low[u]=inc; stack[++top]=u; ins[u]=1; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(!dfn[v]) {dfs(v); low[u]=min(low[u],low[v]);} else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { cnt++; while(1) { pl[stack[top]]=cnt; ins[stack[top]]=0; top--; if(stack[top+1]==u) break; } }}int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++){idc+=2; id[i]=idc;} for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(id[u]^1,id[v]); } for(int j=1;j<=k;j++) { int cn; scanf("%d",&cn); for(int i=1;i<=cn;i++) { int x; scanf("%d",&x); int pre=idc; idc+=2; add(id[x],idc); if(i!=1) { add(id[x],pre^1); //pre->id[x] add(pre,idc); } } } for(int i=2;i<=idc;i++) if(!dfn[i]) dfs(i); bool flag=0; for(int i=1;i<=n;i++) if(pl[id[i]]==pl[id[i]^1]){flag=1; break;} if(flag) printf("NIE\n"); else printf("TAK\n"); return 0;}
- bzoj3495 PA2010 Riddle(2-SAT 前缀优化建边)
- 【2-SAT+前缀优化建图】BZOJ3495 PA2010 Riddle
- [BZOJ3495][PA2010][2-SAT]Riddle
- 【前后缀优化建图+2-SAT】BZOJ3495(PA2010)[Riddle]题解
- bzoj 3495: PA2010 Riddle 2-sat
- [BZOJ]3495: PA2010 Riddle 2-SAT
- [BZOJ]3495 Riddle 2-Sat 前缀和优化
- UOJ #210. 【UER #6】寻找罪犯 2-sat 前缀优化建边 详解
- [二分 前缀优化建图 2-SAT] Codeforces 587D. Duff in Mafia
- [UOJ]210 寻找罪犯 2-Sat 前缀和优化
- [线段树 & 前缀 优化建图 二分 2-SAT] CF Gym100159 facebook-hacker-cup-2012 I. Unfriending
- [二分答案 2-SAT验证 前缀后缀优化建图 线段树优化建图] Codeforces gym 100159 Facebook Hacker Cup 2012 I. Unfriending
- UOJ210【UER #6】寻找罪犯 (2-SAT前后缀优化建边)
- riddle
- 2sat建边总结
- [(可持久化)字典树 优化建图][2-SAT] LOJ#6036. && 雅礼集训 2017 Day4. 编码
- POJ3678 HDU4421 2-sat的建边
- codeforces896A Nephren gives a riddle (dfs)
- shiro01
- win10内置Linux子系统安装GPU版本TensorFlow
- lintcode 20. 骰子求和 动态规划
- python之迭代器和生成器
- Maplab框架介绍(一)
- bzoj3495 PA2010 Riddle(2-SAT 前缀优化建边)
- 基于ubuntu(阿里云)的nginx+uwsgi+django的服务器搭建(到处是坑)
- django为了解决同一个项目不同app下Templates冲突的解决方法
- Android函数响应式编程——必学的RxJava错误处理操作符catch、retry
- C扩展语法一:语句内嵌表达式
- 不用功能键进入BIOS
- 树莓派(RPi) CentOS7安装Nginx
- java基本数据类型
- 小笔记 DLL导出 和 Lib引用