313. [POI2001] 和平委员会
★★☆ 输入文件:spo.in
输出文件:spo.out
评测插件
时间限制:1 s 内存限制:128 MB
题目描述
根据宪法,Byteland民主共和国的公众和平委员会应该在国会中通过立法程序来创立。 不幸的是,由于某些党派代表之间的不和睦而使得这件事存在障碍。
此委员会必须满足下列条件:
- 每个党派都在委员会中恰有1个代表,
- 如果2个代表彼此厌恶,则他们不能都属于委员会。
每个党在议会中有2个代表。代表从1编号到2n。 编号为2i-1和2i的代表属于第I个党派。
任务
写一程序:
- 从文本文件读入党派的数量和关系不友好的代表对,
- 计算决定建立和平委员会是否可能,若行,则列出委员会的成员表,
- 结果写入文本文件。
输入
在文本文件的第一个行有2非负整数n和m。 他们各自表示:党派的数量n,1 < =n < =8000和不友好的代表对m,0 <=m <=20000。 在下面m行的每行为一对整数a,b,1<=a<b<=2n,中间用单个空格隔开。 p="" 它们表示代表a,b互相厌恶。<="">
输出
如果委员会不能创立,文本文件中应该包括单词NIE。若能够成立,文本文件SPO.OUT中应该包括n个从区间1到2n选出的整数,按升序写出,每行一个,这些数字为委员会中代表的编号。如果委员会能以多种方法形成,程序可以只写他们的某一个。
样品输入
3 2 1 3 2 4
样品输出
1 4 5
分析
2-sat问题模板题。
算法实现:
- 连边
- tarjan
- 判可行性,即同一集合中的两个点是否同属一个强连通块
- 缩点建新图,连反边
- 拓扑序,若当前点没有被访问过,则选择该点,不选择其另外的点
详细的文章中有,文章 :http://blog.csdn.net/jarjingx/article/details/8521690
code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<vector> 6 7 #define oth(x) x&1?x+1:x-1 8 9 using namespace std; 10 11 const int N = 20010; 12 13 struct Edge{ 14 int to,nxt; 15 }e[50010]; 16 int head[N],dfn[N],low[N],st[N],bel[N]; 17 bool vis[N]; 18 int ru[N],q[N],opp[N],pr[N]; 19 int tot_edge,n,nn,m,tot_node,top,cnt_block,L,R; 20 vector<int>mp[N]; 21 22 inline char nc() { 23 static char buf[100000],*p1 = buf,*p2 = buf; 24 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 25 } 26 inline int read() { 27 int x = 0,f = 1;char ch = nc(); 28 for (; ch<‘0‘||ch>‘9‘; ch=nc()) if(ch==‘-‘) f=-1; 29 for (; ch>=‘0‘&&ch<=‘9‘; ch=nc()) x=x*10+ch-‘0‘; 30 return x * f; 31 } 32 33 void add_edge(int u,int v) { 34 e[++tot_edge].to = v;e[tot_edge].nxt = head[u];head[u] = tot_edge; 35 } 36 37 void tarjan(int u) { 38 dfn[u] = low[u] = ++tot_node; 39 st[++top] = u; 40 vis[u] = true; 41 for (int i=head[u]; i; i=e[i].nxt) { 42 int v = e[i].to; 43 if (!dfn[v]) { 44 tarjan(v); 45 low[u] = min(low[v],low[u]); 46 } 47 else if (vis[v]) 48 low[u] = min(dfn[v],low[u]); 49 } 50 if (low[u] == dfn[u]) { 51 ++cnt_block; 52 do { 53 vis[st[top]] = false; 54 bel[st[top]] = cnt_block; 55 top--; 56 } while (st[top+1] != u); 57 } 58 } 59 void toposort() { 60 L = 1;R = 0; 61 for (int i=1; i<=cnt_block; ++i) 62 if (ru[i]==0) q[++R] = i; 63 while (L <= R) { 64 int u = q[L++]; 65 if (pr[u] != 0) continue; 66 pr[u] = 1;pr[opp[u]] = 2; 67 int sz = mp[u].size(); 68 for (int i=0; i<sz; ++i) { 69 int v = mp[u][i]; 70 ru[v]--; 71 if (ru[v]==0) q[++R] = v; 72 } 73 } 74 } 75 bool work() { 76 for (int i=1; i<=nn; ++i) { 77 if (!dfn[i]) tarjan(i); 78 } 79 for (int i=1; i<=nn; ++i) { 80 if (bel[i] == bel[oth(i)]) return false; 81 opp[bel[i]] = bel[oth(i)]; 82 opp[bel[oth(i)]] = bel[i]; 83 } 84 for (int u=1; u<=nn; ++u) { 85 for (int i=head[u]; i; i=e[i].nxt) { 86 int v = e[i].to; 87 if (bel[u] != bel[v]) { 88 ru[bel[u]] ++; 89 mp[bel[v]].push_back(bel[u]); 90 } 91 } 92 } 93 toposort(); 94 return true; 95 } 96 int main () { 97 freopen("spo.in","r",stdin); 98 freopen("spo.out","w",stdout); 99 n = read(),m = read();nn = n<<1; 100 for (int i=1; i<=m; ++i) { 101 int a = read(),b = read(); 102 add_edge(a,oth(b)); 103 add_edge(b,oth(a)); 104 } 105 if (work()) { 106 for (int i=1; i<=nn; ++i) 107 if (pr[bel[i]]==1) printf("%d\n",i); //- 108 } 109 else puts("NIE"); 110 return 0; 111 }
再放一发搜索代码
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 #define others(x) x&1?x+1:x-1 6 7 using namespace std; 8 9 const int N = 20010; 10 11 struct Edge{ 12 int to,nxt; 13 }e[50010]; 14 int head[N],mark[N],q[N]; 15 int tot,c,n,m; 16 17 inline char nc() { 18 static char buf[100000],*p1 = buf,*p2 = buf; 19 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 20 } 21 inline int read() { 22 int x = 0,f = 1;char ch = nc(); 23 for (; ch<‘0‘||ch>‘9‘; ch=nc()) if(ch==‘-‘) f=-1; 24 for (; ch>=‘0‘&&ch<=‘9‘; ch=nc()) x=x*10+ch-‘0‘; 25 return x * f; 26 } 27 28 void add_edge(int u,int v) { 29 e[++tot].to = v;e[tot].nxt = head[u];head[u] = tot; 30 } 31 bool dfs(int u) { 32 if (mark[u] != 0) return mark[u] % 2; 33 mark[u] = 1;mark[others(u)] = 2; 34 q[++c] = u; 35 for (int i=head[u]; i; i=e[i].nxt) { 36 int v = e[i].to; 37 if (!dfs(v)) return false; 38 } 39 return true; 40 } 41 bool work() { 42 for (int i=1; i<=(n<<1); ++i) { 43 if (mark[i]) continue; 44 c = 0; 45 if (!dfs(i)) { 46 for (int j=1; j<=c; ++j) 47 mark[q[j]] = mark[others(q[j])] = 0; 48 if (!dfs(others(i))) return false; 49 } 50 } 51 return true; 52 } 53 54 int main () { 55 freopen("spo.in","r",stdin); 56 freopen("spo.out","w",stdout); 57 n = read(),m = read(); 58 for (int i=1; i<=m; ++i) { 59 int a = read(),b = read(); 60 add_edge(a,others(b)); 61 add_edge(b,others(a)); 62 } 63 if (work()) { 64 for (int i=1; i<=(n<<1); ++i) 65 if (mark[i]==1) printf("%d\n",i); 66 } 67 else puts("NIE"); 68 return 0; 69 }