UOJ#210. 【UER #6】寻找罪犯 2-sat
#210. 【UER #6】寻找罪犯
想法:2-sat模型。每个人拆点,分别表示为犯人、非犯人。每个句供词拆点,分别表示真话、假话。供词与对应人的点连双向边。假如$x_i$非犯人,那么连向他的所有真供词。一个假供词意味着至少一个犯人以及这个人的其他供词为真。于是连边。优化连边就可以用前缀,后缀的方式优化。
复杂度$O(n+m)$,常数有点大...
#include< algorithm >
#include< cstdio >
#include< vector > #define gec getchar
#define FILE(F) freopen(F".in","r",stdin),freopen(F".out","w",stdout)
#define DEBUG fprintf(stderr,"Passing [%s] in Line (%d)\n",__FUNCTION__,__LINE__); typedef long long ll;
template
inline void read(T&x)
{
x=0;bool f=0;char c=gec();
for(;c<'0'||c>'9';c=gec())f=(c=='-');
for(;c>='0'&&c<='9';c=gec())x=x*10+c-'0';
x=f?-x:x;
}
const int N(100010),M(100010),MAXN((N+M+M)<<1),MAXM(M*20);
int n,m,x,y,t;
std::vectorconf[N];
//(i<<1)为正点,(i<<1)|1为负点 [2,n<<1|1]为犯人,[n<<1+2,n<<1|1+(m<<1|1)]为供词
struct Node{int nd,nx;}bot[MAXM];
int tot,first[MAXN],total,col[MAXN],ant,limt;
void add(int a,int b)
{bot[++tot]=(Node){b,first[a]};first[a]=tot;}
void addedge(int a,int b){add(a,b);add(b,a);}
int min(int a,int b){return a>b?b:a;}
namespace Tarjan
{
int low[MAXN],dfn[MAXN],st[MAXN],tp,cnt;bool vis[MAXN],flag[MAXN];
void Dfs(int x)
{
low[x]=dfn[x]=++cnt; vis[x]=flag[x]=1; st[++tp]=x;
for(int v=first[x];v;v=bot[v].nx)
{
if(!vis[bot[v].nd])
{
Dfs(bot[v].nd);
low[x]=min(low[x],low[bot[v].nd]);
}else if(flag[bot[v].nd])low[x]=min(low[x],dfn[bot[v].nd]);
}
if(low[x]==dfn[x])
for(ant++;flag[x];tp--)flag[st[tp]]=0,col[st[tp]]=ant;
}
void run()
{
for(int i=2;i<=total;i++)
if(!vis[i])Dfs(i);
}
}
namespace Coloring
{
std::vectorbelong[MAXN];
int nx[MAXM],nd[MAXM],head[MAXN],color[MAXN],in[MAXN],tot,st[MAXN],tp,now,no;
//color 1:不选,2选,0未知
void add(int a,int b)
{nd[++tot]=b; nx[tot]=head[a]; head[a]=tot; in[b]++;}
bool Get_plan()
{
for(int i=1;i<=n+m;i++)
if(col[i<<1]==col[i<<1|1])return false;
for(int i=2;i<=total;i++)
{
if(i<=limt)belong[col[i]].push_back(i);//不用管虚点
for(int v=first[i];v;v=bot[v].nx)
if(col[i]!=col[bot[v].nd])add(col[bot[v].nd],col[i]);
}
for(int i=1;i<=ant;i++)
if(!in[i])st[++tp]=i;
while(tp)
{
now=st[tp--];
no=color[now];
for(int v=0,sz=belong[now].size();v<sz;v++)
if(color[col[belong[now][v]^1]]==2)no=1;
color[now]=no?1:2;
for(int v=head[now];v;v=nx[v])
{
in[nd[v]]--; color[nd[v]]|=no;
if(!in[nd[v]])st[++tp]=nd[v];
}
}
for(int i=1;i<=n;i++)
if(color[col[i<<1|1]]==2)st[++tp]=i;
std::sort(st+1,st+1+tp);
printf("%d\n",tp);
for(int i=1;i<=tp;i++)
printf("%d ",st[i]);
return true;
} }
int main()
{
#ifndef ONLINE_JUDGE
FILE("C");
#endif
read(n);read(m);
for(int i=1,now;i<=m;i++)
{
read(x),read(y),read(t);
now=(i+n)<<1;
conf[x].push_back(now);
addedge(now,(y<<1)|(t^1));
addedge(now|1,(y<<1)|t);
}
limt=total=(n+m)<<1|1;
for(int i=1,last;i<=n;i++)
{
/*for(int v=0,sz=conf[i].size();v<sz;v++)
{
for(int u=0;u<sz;u++)
if(u!=v)add(conf[i][v]^1,conf[i][u]);
add(conf[i][v]^1,i<<1|1);
add(i<<1,conf[i][v]);
}*/
last=0;
for(int v=0,sz=conf[i].size();v<sz;v++)
{
if(last)add(conf[i][v]^1,last);
if(last)add(last+1,last);
add(last=++total,conf[i][v]);
add(conf[i][v]^1,i<<1|1);
}
last=0;
for(int sz=conf[i].size(),v=sz-1;v>=0;v--)
{
if(last)add(conf[i][v]^1,last);
if(last)add(last+1,last);
add(last=++total,conf[i][v]);
add(i<<1,conf[i][v]);
}
}
Tarjan::run();
if(!Coloring::Get_plan())printf("Impossible");
return 0;
}
UOJ#210. 【UER #6】寻找罪犯 2-sat的更多相关文章
- uoj #210. 【UER #6】寻找罪犯【2-SAT】
首先最直观的,列一排是罪犯一排不是罪犯,对于一个条件u说v(0是1否)f罪犯,如果u不是,那么vf罪犯:如果u是,枚举他说谎的一条wg罪犯,令w(g^1)罪犯连其他条的vf 但是这样有个电度数方,会炸 ...
- 【UOJ #210】【UER #6】寻找罪犯
题目描述 通过一些不可描述的方式,妹滋滋算出了 51% 的得票率,于是就她就把这个公开给了广大用户 —— UOJ 解散已成定局. 几个小时后,UOJ 创始人伏特跳蚤国王宣布辞职,即日起退出 UOJ 团 ...
- [UOJ210]寻找罪犯
2-sat神题.. 告诉是2-sat我也完全想不到正解. 看了看题解其实一步步分析也不算很难 这个题首先是要围绕每个人是否是犯人和每句话是否是真话来思考 首先要明确的是: 1.好人不说谎话 2.说了谎 ...
- UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
题目链接 http://uoj.ac/contest/47/problem/455 题解 模拟费用流,一个非常神奇的东西. 本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞 ...
- [UOJ#245][UER#7]天路(近似算法)
允许5%的相对误差,意味着我们可以只输出$\log_{1.05} V$种取值并保证答案合法.并且注意到答案随着区间长度而单增,故取值不同的答案区间是$O(\log_{1.05} V)$的. 于是初始x ...
- 2-sat问题学习记录
如果你不知道什么是sat问题,请看以下问答. Q:sat问题是什麽?A:首先你有n个布尔变量,然后你有一个关于这n个布尔变量的布尔表达式,问你,如果让你随意给这n个布尔变量赋值,这个布尔表达式能否成立 ...
- P4478 [BJWC2018]上学路线
Description 小B 所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M). 小B 家住在西南角,学校在东北角.现在有T 个路口进行施工,小B 不能通过这些路口.小B ...
- Tarjan/2-SAT学习笔记
Tarjan/2-SAT Tags:图论 作业部落 评论地址 Tarjan 用来求割边或者割点,求点双联通分量或者边双联通分量 点双联通分量:两个点之间有两条点不相交的路径 边双联通分量:两个点之间有 ...
- Tarjan&2-SAT 总结
\(Tarjan\)&\(2-SAT\) 标签: 知识点总结 安利XZYXZY ps:里面的部分东西来自\(Anson\)和\(yler\)和\(XZY\) 阅读体验:https://zybu ...
随机推荐
- MySQL中ORDER BY与LIMIT一起使用(有坑)
1. 现象与问题 ORDER BY排序后,用LIMIT取前几条,发现返回的结果集的顺序与预期的不一样 下面是我遇到的问题: 可以看到,带LIMIT与不带LIMIT的结果与我预期的不一样,而且“很不可 ...
- [Java]构造函数内部多态的行为所引起的灾难
构造函数内部的多态行为所产生的意想不到的结果 一.Java版本 1 package com.company; 2 import static com.brianyi.util.Print.*; 3 4 ...
- 【转载】Hyperledger学习小结
Hyperledger学习小结 自学Hyperledger Composer也有段时间了,是时候对所学的知识总结一下了.因为没有实际项目参与的话,差不多也就到此为止了.后续可能会去了解一下以太坊的技术 ...
- poj 1655 Balancing Act(找树的重心)
Balancing Act POJ - 1655 题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. /* 找树的重心可以用树形dp或 ...
- InfoQ —— 腾讯游戏大数据服务场景与应用
简介 周东祥,本人从2010年毕业进入腾讯互动娱乐部门工作,一直致力在腾讯游戏运营开发工作.先后负责SAP业务受理系统,盗号自助系统,元数据系统以及近2年在腾讯游戏大数据运营开发中积累大量的大数据开发 ...
- AT2582 Mirrored
传送门 智障爆搜题 可以发现题目给出的式子可以移项 然后就是\(rev(N)-N=D\) 然后假设\(N=a_1*10^{n-1}+a_2*10^{n-2}+...+a_{n}\) 那么\(rev(N ...
- PHP下载远程图片的几种方法总结
1. 使用file_get_contents function dlfile($file_url, $save_to) { $content = file_get_contents($file_url ...
- day13列表推导式作业详解
1.day13题目 2,用列表推导式做下列小题 (1)过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 (2)求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表 (3)求M ...
- little w and Soda(思维题)
链接:https://ac.nowcoder.com/acm/contest/297/A 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5242 ...
- Floyed-Warshall算法(求任意两点间最短距离)
思路:感觉有点像暴力啊,反正我是觉得很暴力,比如求d[i][j],用这个方法求的话,就直接考虑会不会经过点k(k是任意一点) ,最终求得最小值 看代码 #include<iostream> ...