本文共 2141 字,大约阅读时间需要 7 分钟。
每个代表要么被选中,要么不被选中,标记为 t r u e true true或 f a l s e false false
为了方便,规定 x x x为 t r u e true true时编号 x x x,为 f a l s e false false时编号 x + b a s e x+base x+base
对于相互厌恶的 u , v u,v u,v来说 u , v u,v u,v不能同时为 t r u e true true
若 u = t r u e u=true u=true则 v = f a l s e v=false v=false,连边 ( u , v + b a s e ) (u,v+base) (u,v+base)
若 v = t r u e v=true v=true则 u = f a l s e u=false u=false,连边 ( v , u + b a s e ) (v,u+base) (v,u+base)
对于属于一个党派的代表 u , v u,v u,v来说恰好有一个为 t r u e true true
若 u = t r u e u=true u=true则 v = f a l s e v=false v=false
若 u = f a l s e u=false u=false则 v = t r u e v=true v=true
若 v = t r u e v=true v=true则 u = f a l s e u=false u=false
若 v = f a l s e v=false v=false则 u = t r u e u=true u=true
这样连边,跑 2 − S A T 2-SAT 2−SAT即可
但是仔细观察发现可以优化,因为 i ∗ 2 − 1 i*2-1 i∗2−1和 i ∗ 2 i*2 i∗2的关系一定是对立的
厌恶的两个人 l , r l,r l,r关系也是对立的,我们只需要彼此连边就可以,最后只要不在一个连通分量即可,不需要提前确定哪个点是 t r u e , f a l s e true,false true,false
每次选择拓扑序大的就好了
#includeusing namespace std;const int maxn = 3e6+10;struct edge{ int to,nxt;}d[maxn]; int head[maxn],cnt=1;void add(int u,int v){ d[++cnt] = ( edge ){ v,head[u]},head[u] = cnt;}int n,m,base;int dfn[maxn],low[maxn],stac[maxn],vis[maxn],scc[maxn],sc,id,top;void tarjan(int u){ vis[u] = 1, stac[++top] = u, low[u] = dfn[u] = ++id; for(int i=head[u];i;i=d[i].nxt ) { int v = d[i].to; if( !dfn[v] ) { tarjan(v); low[u] = min( low[u],low[v] ); } else if( vis[v] ) low[u] = min( low[u],dfn[v] ); } if( low[u]==dfn[u] ) { sc++; int temp; while( temp = stac[top--] ) { scc[temp] = sc, vis[temp] = 0; if( temp == u ) break; } }}int ok[maxn];int main(){ cin >> n >> m; base = n+n; for(int i=1;i<=n;i++) { int u = i*2-1, v = u+1; add(u,v+base); add(u+base,v); add(v,u+base); add(v+base,u); } for(int i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); add(l,r+base); add(r,l+base); } for(int i=1;i<=n+n+base;i++) if( !dfn[i] ) tarjan(i); for(int i=1;i<=n+n;i++) { if( scc[i]==scc[i+base] ){ puts("NIE"); return 0; } if( scc[i]>scc[i+base] ) ok[i] = 2;//false else ok[i] = 1;//true } for(int i=1;i<=n+n;i++) if( ok[i]==1 ) cout << i << endl;}
转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/115428004 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!