Hoj 1917 Peaceful Commission

来源:互联网 发布:linux删除进程命令 编辑:程序博客网 时间:2024/06/03 22:47

题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=1917

2-sat问题。

如果a和b矛盾,那么a向b的反面连一条线。

以此建立了一颗有向图,然后对此图求强连通分量后缩点,反向连线后形成一个DAG图。

然后对此图求拓扑排序即可。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <stack>#include <queue>#include <algorithm>#include <iostream>using namespace std;#define Maxn (8005 * 2)#define Maxm (40005 * 2)struct Edge{int a,b;}edge[Maxm],rEdge[Maxm];int first[Maxn],next[Maxm];int rFirst[Maxn],rNext[Maxm];int total,rTotal;//scc相关int sccno[Maxn];bool instack[Maxn];int dfn[Maxn];int low[Maxn];int dfs_clock;int scc_cnt;stack <int> st;//2sat相关int in[Maxn];int conflict[Maxn];int col[Maxn];int ans[Maxn];void addEdge(int a,int b){edge[total].a = a,edge[total].b = b;next[total] = first[a];first[a] = total++;}void addREdge(int a,int b){rEdge[rTotal].a = a,rEdge[rTotal].b = b;rNext[rTotal] = rFirst[a];rFirst[a] = rTotal++;}void init(){total = 0;memset(first,-1,sizeof(first));}void rInit(){rTotal = 0;memset(rFirst,-1,sizeof(rFirst));}void tarjan(int u){  dfn[u] = low[u] = ++dfs_clock;  st.push(u);  instack[u] = true;  for(int i=first[u];i!=-1;i=next[i])  {    int v = edge[i].b;    if(!dfn[v])    {      tarjan(v);      low[u] = min(low[u],low[v]);    }    else if(instack[v])    {      low[u] = min(low[u],dfn[v]);    }  }  if(dfn[u] == low[u])  {    scc_cnt++;    while(1)    {      int v = st.top();      st.pop();      instack[v] = false;      sccno[v] = scc_cnt;      if(u == v) break;    }  }}void find_scc(int start,int n){scc_cnt = dfs_clock = 0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));  memset(instack,false,sizeof(instack));  while(!st.empty())  {    st.pop();  }  for(int i=start;i<=n;i++)  {    if(!dfn[i]) tarjan(i);  }}bool twoSet(int start,int n){find_scc(start,n);for(int i=start;i<=n;i++){if(sccno[i] == sccno[i^1]) return false;}for(int i=start;i<=n;i++){conflict[sccno[i]] = sccno[i^1];conflict[sccno[i^1]] = sccno[i];}memset(in,0,sizeof(in));memset(col,0,sizeof(col));memset(ans,0,sizeof(ans));for(int i=start;i<=n;i++){for(int j=first[i];j!=-1;j=next[j]){int v = edge[j].b;if(sccno[i]!=sccno[v]){addREdge(sccno[v],sccno[i]);in[sccno[i]]++;}}}queue <int> q;for(int i=1;i<=scc_cnt;i++){if(in[i]==0) q.push(i);}while(!q.empty()){int u = q.front();q.pop();if(col[u] == 0) col[u] = 1,col[conflict[u]] = -1;for(int i=rFirst[u];i!=-1;i=rNext[i]){int v = rEdge[i].b;in[v]--;if(in[v]==0) q.push(v);}}for(int i=start;i<=n;i++){if(col[sccno[i]] == 1) ans[i] = 1;}return true;}int main(){#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);#endifint n,m;int a,b;while(scanf(" %d %d",&n,&m)!=EOF){init(),rInit();for(int i=1;i<=m;i++){scanf(" %d %d",&a,&b);a--;b--;addEdge(a,b^1);addEdge(b,a^1);}if(!twoSet(0,2*n-1)) {puts("NIE");continue;}for(int i=0;i<2*n;i++){if(ans[i]) printf("%d\n", i+1);}}return 0;}


原创粉丝点击