【2-SAT】The Ministers’ Major Mess UVALive – 4452

题目链接:https://cn.vjudge.net/contest/209474#problem/C

题目大意:

一共有m个提案,n个政客,每个政客都会对一些提案(最多四个)提出自己的意见——通过或者不通过。一个政客获得满意结果,当且仅当他的意见被满足了超过(注意是超过,即大于)一半,请问有没有这样的方案,使n个政客都满意?如果存在,输出所有方案。(这个所有的意思是一个提案如果只能是“通过”决策(在所有方案里都是通过),输出’y‘,只能不通过输出’n’,可以通过也可以不通过(有的方案是y,有的是n)输出‘?’)

 

解题思路:

本来想写在《浅谈2-SAT》里,想了想由于这道题比较巧妙,还是单独提出来写。巧妙之处在于1、寻找所有可行方案。2、问题到标准模型的转化。

先谈一下第二点。

一个政客满意,当且仅当他有一半以上的观点被采纳。也就是说,对于只提出一个提案和两个提案的人,只有他提出的所有观点都被采纳,这个人才会满意。对于提出三个提案的人,至少要满足两个观点(最多有一个不满足);对于提出四个提案的人,至少要满足三个观点(最多有1个不满足)。

每个提案有通过和不通过两种互斥状态,对于观点数量小于等于2的人,他所提出的提案有固定状态(不对称图),对于观点数大于等于3的人,我们如果令其中一个观点为不满足,那么其他的观点都必须满足。

由此我们建立了一个部分确定值的2-SAT图像。

再谈第一点。

这道题的难点其实我自我感觉在第一点。令人惊讶的是,第一点并没有什么高端的处理方法,仅仅是暴力枚举,如果一个提案两种状态的2-SAT图像都成立,那么就是?,只成立一种就是对应结果。如果两种都不成立那么就无解。

 

下面放有详细注释的9msAC代码并附了几组数据debug(欢迎hack):

 

  1 /* by Lstg */
  2 /* 2018-03-07 00:33:58 */
  3 
  4 #include<stdio.h>
  5 #include<iostream>
  6 #include<vector>
  7 #include<string.h>
  8 #define MAXN 5100
  9 using namespace std;
 10 
 11 vector<int>g[MAXN];
 12 
 13 bool mark[MAXN],f[MAXN];
 14 int stk[MAXN],top,n,lq[MAXN];
 15 char ans[500];
 16 
 17 int _max(int a,int b){return a>b?a:b;}
 18 int _abs(int x){return x<0?-x:x;}
 19 
 20 void _clean(){
 21     
 22     for(int i=0;i<=2*n+1;i++){
 23         g[i].clear();
 24         mark[i]=0;
 25         f[i]=false;
 26     }
 27 }
 28 
 29 bool _dfs(int x){
 30     
 31     if(mark[x^1])return false;
 32     if(mark[x])return true;
 33     mark[x]=true;
 34     stk[++top]=x;
 35     for(int i=0;i<g[x].size();i++)
 36         if(!_dfs(g[x][i]))return false;
 37     return true;
 38 }
 39 
 40 bool _Twosat(){
 41     
 42     for(int i=2;i<=2*n+1;i+=2)
 43         if(!mark[i]&& !mark[i+1]){
 44             top=0;
 45             if(!_dfs(i)){
 46                 while(top)
 47                     mark[stk[top--]]=false;
 48                 if(!_dfs(i+1))return false;
 49             }
 50         }
 51     return true;
 52 }
 53 
 54 void _addside(int k){
 55     
 56     for(int i=1;i<=k;i++)
 57         for(int j=1;j<=k;j++)
 58             if(j!=i)
 59                 g[lq[i]^1].push_back(lq[j]);//lq[i]^1表示状态的反面,即不满足。在此情况下其他的状态必须满足
 60                 
 61 }
 62 
 63 bool _check(){
 64     
 65     int i;
 66     for(i=2;i<=2*n+1;i++)
 67         if(f[i]&&!_dfs(i))return false;//如果不能满足固定的状态值就无解
 68     memcpy(f,mark,sizeof(mark));//f数组已经没用了,用来当过渡
 69     //printf("n=%d\n",n);
 70     if(!_Twosat())return false;//如果满足了所有固定状态却不能满足整个2-SAT图,无解
 71     //puts("haha!\n");
 72     for(i=1;i<=n;i++){
 73         memcpy(mark,f,sizeof(f));//固定状态都满足的残余2-SAT图作为起始图像
 74         top=0;
 75         if(!(_dfs(2*i)&&_Twosat()))ans[i]='n';/*这里可能有点难理解,我写的确实很绕,没必要跟我一样,
 76 这里的意思是如果不满足该提案通过,那么这个提案就一定是不通过(因为无解的情况已经全排除了,一定有解,这个提案通过却不满足图像,那么这个提案一定通不过)*/
 77         else{//如果提案可以通过
 78             memcpy(mark,f,sizeof(f));
 79             top=0;
 80             if(_dfs(2*i+1)&&_Twosat())ans[i]='?';//验证是否也可以不通过
 81             else ans[i]='y';
 82         }
 83 
 84     }
 85     return true;//返回有解
 86 }
 87             
 88     
 89 
 90 int main(){
 91     
 92     //freopen("C.txt","w",stdout);
 93     int m,k,i,j,a,x;
 94     char ch[8];
 95     int T=0;
 96     while(true){
 97         
 98         scanf("%d%d",&n,&m);
 99         if(m+n==0)return 0;
100         _clean();
101         
102         for(i=1;i<=m;i++){
103             scanf("%d",&k);
104             
105             for(j=1;j<=k;j++){
106                 scanf("%d%s",&x,ch);
107             
108                 a=(ch[0]=='y'?0:1);//2*ii表示通过,2*ii+1表示不通过
109                 
110                 if(k<=2)f[x*2+a]=true;//f数组表示有确定状态的提案
111                 else lq[j]=x*2+a;//lq数组为一会儿构图的媒介
112             }
113             if(k>=3)_addside(k);//用lq数组构图
114         }
115         printf("Case %d: ",++T);
116         if(!_check())printf("impossible\n");
117         else{
118             for(i=1;i<=n;i++)
119                 putchar(ans[i]);
120             putchar(10);
121         }
122     }
123     return 0;
124 }
125 /*
126 1 1
127 1 1 n
128 1 1 
129 1 1 y
130 
131 3 2
132 3 1 y 2 y 3 n
133 3 1 n 2 n 3 y
134 
135 3 2
136 3 1 y 2 n 3 n
137 3 1 n 2 n 3 n
138 
139 3 2
140 3 1 y 2 y 3 n
141 3 1 y 2 n 3 n
142 
143 4 2
144 4 1 y 2 y 3 n 4 n
145 3 2 n 3 n 4 n
146 3 2
147 3 1 y 2 y 3 n
148 3 1 y 2 n 3 n
149 
150 */

 

posted @ 2018-03-07 18:12  落雨。  阅读(256)  评论(0编辑  收藏  举报