• 【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);
     70     if(!_Twosat())return false;//如果满足了所有固定状态却不能满足整个2-SAT图,无解
     71     //puts("haha!
    ");
     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
    ");
    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 */
  • 相关阅读:
    H.265网页播放器EasyPlayer获取视频流正常,但是播放出现黑屏是什么原因?
    sql server设置允许远程连接的方法
    SQL Server 添加、修改和删除表格字段
    IDEA设置编辑器主题
    Idea中如何查看项目配置
    IDEA常用快捷键
    SQL Server : 18456报错
    SQL Server : 排序规则冲突collate Chinese_PRC_90_CI_AI
    excel表格如何设置下拉选项
    EXCEL插入图片批注
  • 原文地址:https://www.cnblogs.com/L-Excalibur/p/8524479.html
Copyright © 2020-2023  润新知