题意:每个人最多对4个法案提意见,问是否存在一种方案,使得每个人的意见通过一半以上。若可以通过一半以上,输出每个方案可能的结果(一定通过/一定不通过/两个结果都有可能)
思路:意见为1/2时,全部通过,意见为3/4时,至多否决一个意见,从而转化为“意见”型2-sat问题
“意见”型变量
1.先把意见用变量表示:把每个人的意见表示成数x的形式(x是某个布尔变量成立(x=2*y+1)/不成立(x=2*y)),则该意见成立则为x,不成立则为x^1
2.再根据意见间的逻辑关系,表示成语句。
意见型语句:
1.k个意见中至多有一个不成立 add(xi^1,xj)
2.k个意见中至多有一个成立 add(xi,xj^1)
3.k个意见全部成立 add(xi^1,xi)
4.k个意见全部不成立 add(xi,xi^1)
2-SAT算法对dfs的理解:dfs(u):把某个布尔变量赋值为u后,整个图是否引起矛盾。
通过dfs可以判断是否可以让某个布尔变量取特定的值
<span style="font-size:14px;">#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#define maxn 5010
#define INF 1<<28
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,m,adv[maxn],S[maxn<<2],c;
vector<int> g[maxn];
bool mark[maxn<<2];
void add(int u,int v) { g[u].push_back(v); }
void build(int k){
if(k==1) add(adv[1]^1,adv[1]);
if(k==2) add(adv[1]^1,adv[1]),add(adv[2]^1,adv[2]);
if(k==3||k==4) for(int i=1;i<=k;i++) for(int j=1;j<=k;j++) if(i!=j) add(adv[i]^1,adv[j]);
}
bool dfs(int u){//u成立:判断该图是否产生矛盾
if(mark[u^1]) return false;
if(mark[u]) return true;
mark[u]=1,S[c++]=u;
for(int i=0;i<g[u].size();i++) if(!dfs(g[u][i])) return false;
return true;
}
bool judge_2sat(){
for(int i=0;i<2*n;i+=2){
if(mark[i]&&mark[i^1]) return false;
else if(!mark[i]&&!mark[i^1]){
c=0;
if(!dfs(i)){
while(c) mark[S[--c]]=0;//还原
if(!dfs(i^1)) return false;
}
}
}
return true;
}
<strong>bool ok(int u){
mem(mark,0);
if(!dfs(u)) return false;
return true;
}
</strong>
int main(){
int T=0;
//freopen("a.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF){
if(!n&&!m) break;
for(int i=0;i<2*n;i++) g[i].clear();//点的数量写成了n!
for(int i=1;i<=m;i++){
int k,a;char b[3]; scanf("%d",&k);
for(int j=1;j<=k;j++){
scanf("%d%s",&a,b); a-=1;//id变化范围0-(n-1)
if(b[0]=='y') adv[j]=2*a+1; else adv[j]=2*a;
}
build(k);//k个意见至少成立一半
}
printf("Case %d: ",++T);
mem(mark,0);
if(!judge_2sat()) { printf("impossible\n"); continue; }
for(int i=0;i<n;i++){
bool f1=ok(2*i),f2=ok(2*i+1);
if(f1&&f2) printf("?");
else if(f1&&!f2) printf("n");
else if(!f1&&f2) printf("y");
}
printf("\n");
}
return 0;
}</span>