[题解]POI 0106 Peaceful Commission 和平委员会

【题目描述】 [Special Judge]

根据宪法,Byteland民主共和国的公众和平委员会应该在国会中通过立法程序来创立。 不幸的是,由于某些党派代表之间的不和睦而使得这件事存在障碍。此委员会必须满足下列条件:   

(1)每个党派都在委员会中恰有1个代表, 

(2)如果2个代表彼此厌恶,则他们不能都属于委员会。 

每个党在议会中有2个代表。代表从1编号到2n。 编号为2i-1和2i的代表属于第i个党派。  

任务:

写一程序,从文本文件peace.in读入党派的数量和关系不友好的代表对, 计算决定建立和平委员会是否可能,若行,则列出委员会的成员表, 结果写入文本文件peace.out。

【输入】 

第一个行有2非负整数n和m。 他们各自表示:党派的数量n,1 < =n < =8000和不友好的代表对m,0 <=m <=20000。 在下面m行的每行为一对整数a,b,1<=a <b<=2n,中间用单个空格隔开。 它们表示代表a,b互相厌恶。 

【输出】 

如果委员会不能创立,文本文件peace.out中应该包括单词NIE。若能够成立,文本文件peace.out中应该包括n个从区间1到2n选出的整数,按升序写出,每行一个,这些数字为委员会中代表的编号。如果委员会能以多种方法形成,程序可以只写他们的某一个。 

【样例】

peace.in

3 2

1 3

2 4

peace.out

1

4

5

-----------------------------------------------------------------------------------------------------------------------------------

【题解】

一道很裸的2-SAT问题。

考虑建图:我们规定i和_i为同一个党派的两个委员。若i与j有矛盾,则连边(i,_j)和(j,_i)。然后做一次Tarjan找强连通分量,缩图。判断缩图后的每个连通块是否合法,即看i和_i是否在同一个块中。然后对新图进行拓扑排序,自底向上进行选择、删除,最后得解。具体实现参见代码:

  1 #include<iostream> 
  2 #include<cstdio> 
  3 #include<cstring> 
  4 using namespace std; 
  5 #define MAXN 8020 
  6 #define MAXM 20020 
  7 int n,m; 
  8 struct node 
  9 { 
 10     int v; 
 11     node *next; 
 12 }; 
 13 node edge[MAXM*2]; 
 14 node *cnt=&edge[0]; 
 15 node *adj[MAXN]; 
 16 node edge2[MAXM*2]; 
 17 node *cnt2=&edge2[0]; 
 18 node *adj2[MAXN]; 
 19 int dfn[MAXN],low[MAXN],dcnt; 
 20 int stack[MAXN],top; 
 21 int Belong[MAXN],Num[MAXN],opp[MAXN],scc; 
 22 int In[MAXN],q[MAXN],col[MAXN]; 
 23 bool Instack[MAXN],ans[MAXN]; 
 24 inline void Get_int(int &Ret) 
 25 { 
 26     char ch; 
 27     bool flag=false; 
 28     for(;ch=getchar(),ch<'0'||ch>'9';) 
 29         if(ch=='-') 
 30             flag=true; 
 31     for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0'); 
 32     flag&&(Ret=-Ret); 
 33 } 
 34 inline int Get(int x) 
 35 { 
 36     if(x%2) 
 37         return x+1; 
 38     return x-1; 
 39 } 
 40 inline void Addedge(int u,int v) 
 41 { 
 42     node *p=++cnt; 
 43     p->v=v; 
 44     p->next=adj[u]; 
 45     adj[u]=p; 
 46 } 
 47 inline void Addedge2(int u,int v) 
 48 { 
 49     node *p=++cnt2; 
 50     p->v=v; 
 51     p->next=adj2[u]; 
 52     adj2[u]=p; 
 53 } 
 54 void Read() 
 55 { 
 56     Get_int(n); 
 57     n*=2; 
 58     Get_int(m); 
 59     int i,j,k; 
 60     for(i=1;i<=m;i++) 
 61     { 
 62         Get_int(j); 
 63         Get_int(k); 
 64         Addedge(j,Get(k)); 
 65         Addedge(k,Get(j)); 
 66     } 
 67 } 
 68 void Tarjan(int u) 
 69 { 
 70     int v; 
 71     dfn[u]=low[u]=++dcnt; 
 72     stack[++top]=u; 
 73     Instack[u]=true; 
 74     for(node *p=adj[u];p;p=p->next) 
 75     { 
 76         v=p->v; 
 77         if(!dfn[v]) 
 78         { 
 79             Tarjan(v); 
 80             low[u]=min(low[u],low[v]); 
 81         } 
 82         else if(Instack[v]) 
 83             low[u]=min(low[u],dfn[v]); 
 84     } 
 85     if(dfn[u]==low[u]) 
 86     { 
 87         scc++; 
 88         do
 89         { 
 90             v=stack[top]; 
 91             top--; 
 92             Instack[v]=false; 
 93             Belong[v]=scc; 
 94             Num[scc]++; 
 95         }while(v!=u); 
 96     } 
 97 } 
 98 bool Work() 
 99 { 
100     int i; 
101     for(i=1;i<=n;i++) 
102         if(!dfn[i]) 
103             Tarjan(i); 
104     for(i=1;i<=n;i+=2) 
105     { 
106         if(Belong[i]==Belong[i+1]) 
107             return false; 
108         opp[Belong[i]]=Belong[i+1]; 
109         opp[Belong[i+1]]=Belong[i]; 
110     } 
111     int u,v; 
112     for(i=1;i<=n;i++) 
113         for(node *p=adj[i];p;p=p->next) 
114         { 
115             v=p->v; 
116             if(Belong[i]!=Belong[v]) 
117             { 
118                 Addedge2(Belong[v],Belong[i]); 
119                 In[Belong[i]]++; 
120             } 
121         } 
122     int l=0,r=0; 
123     for(i=1;i<=scc;i++) 
124         if(!In[i]) 
125         { 
126             q[r]=i; 
127             r++; 
128         } 
129     while(l<r) 
130     { 
131         u=q[l]; 
132         l++; 
133         if(!col[u]) 
134         { 
135             col[u]=1; 
136             col[opp[u]]=-1; 
137         } 
138         for(node *p=adj2[u];p;p=p->next) 
139         { 
140             v=p->v; 
141             In[v]--; 
142             if(!In[v]) 
143             { 
144                 q[r]=v; 
145                 r++; 
146             } 
147         } 
148     } 
149     for(i=1;i<=n;i+=2) 
150         if(col[Belong[i]]==1) 
151             ans[i]=true; 
152     return true; 
153 } 
154 void Print() 
155 { 
156     if(Work()) 
157     { 
158         int i; 
159         for(i=1;i<=n;i+=2) 
160             if(ans[i]) 
161                 printf("%d\n",i); 
162             else
163                 printf("%d\n",i+1); 
164     } 
165     else
166         printf("NIE\n"); 
167 } 
168 int main() 
169 { 
170     Read(); 
171     Print(); 
172     return 0; 
173 } 

代码没有经过缩减,所以比较冗长,但自以为写得比较清楚。望指导^w^

 

 

 

 

 

 

 

 

 

 

 

posted @ 2013-01-22 21:16  zyy是一只超级大沙茶  阅读(1437)  评论(2)    收藏  举报