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; }