COGS:313. [POI2001] 和平委员会

Posted mjtcn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了COGS:313. [POI2001] 和平委员会相关的知识,希望对你有一定的参考价值。

 

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问题模板题。

算法实现:

  1. 连边
  2. tarjan
  3. 判可行性,即同一集合中的两个点是否同属一个强连通块
  4. 缩点建新图,连反边
  5. 拓扑序,若当前点没有被访问过,则选择该点,不选择其另外的点

详细的文章中有,文章 :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 }
View Code

 

再放一发搜索代码

技术分享图片
 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 }
View Code

 

以上是关于COGS:313. [POI2001] 和平委员会的主要内容,如果未能解决你的问题,请参考以下文章

[POI2001]和平委员会

[Poi2001]和平委员会 理解

HIT 1917 2—SAT

和平委员会

[Poi2000]病毒

P2444 [POI2000]病毒