The Ministers’ Major Mess UVALive - 4452
图论·2-SAT
题目大意:
题目大意:有n个人对m个方案投票,每个人最多只能对其中的4个方案投票(其他的相当于弃权),每一票要么支持要么反对。问是否存在一个最终决定,使得每个投票人都有超过一半的建议被采纳,在所有可能的最终决定中,哪些方案的态度是确定的。
题解:
蒙蒙一开始在想网络流。
其实是一道2-SAT啦。
注意到一个人最多投四个,我们分情况讨论一下:
1.投<=2个:注意题目中说的是严格大于投票的一半,所以必须都采纳。
2.投3~4个:同上,最多不采纳一个。
设xi表示最后是否通过方案i,
第一种直接连2-SAT问题中确定项的边即可,第二种的限制是枚举任意两个组合,这两个中至少有一个成立。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 100005;
int n,m;
char ans[N];
inline int ID(int x,int y){ return (x-1)*2+y; }
struct Edge{
int to,next;
}e[N*2];
int head[N],ec;
void clear(){ memset(head,0,sizeof(head)); ec=0; }
void add(int a,int b){
ec++; e[ec].to=b; e[ec].next=head[a]; head[a]=ec;
}
void add2(int a,int i,int b,int j){
add(ID(a,!i),ID(b,j));
add(ID(b,!j),ID(a,i));
}
bool mark[N]; int c,S[N];
bool dfs(int x){
if(mark[x^1]) return false;
if(mark[x]) return true;
mark[x]=true;
S[c++]=x;
for(int i=head[x];i;i=e[i].next){
if(!dfs(e[i].to)) return false;
}
return true;
}
bool solve(){
memset(mark,0,sizeof(mark));
for(int i=0;i<n*2;i+=2){
if(!mark[i] && !mark[i+1]){
c=0;
bool bo1=dfs(i);
while(c) mark[S[--c]]=false;
c=0;
bool bo2=dfs(i+1);
while(c) mark[S[--c]]=false;
if(bo1 && bo2) ans[i/2]='?';
else if(bo1) ans[i/2]='n';
else if(bo2) ans[i/2]='y';
else return false;
}
}
//D(n); E;
ans[n]='\0';
return true;
}
void build(){
int k,x[5],y[5]; char s[5];
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d%s",&x[i],s);
if(s[0]=='y') y[i]=1; else y[i]=0;
}
if(k<=2){
for(int i=1;i<=k;i++)
add(ID(x[i],!y[i]),ID(x[i],y[i]));
}
else{
for(int i=1;i<=k;i++){
for(int j=i+1;j<=k;j++){
add2(x[i],y[i],x[j],y[j]);
}
}
}
}
int main(){
freopen("a.in","r",stdin);
int cas=0;
while(~scanf("%d%d",&n,&m) && (n||m)){
clear();
for(int i=1;i<=m;i++) build();
if(!solve()){ printf("Case %d: impossible\n",++cas); }
else{ printf("Case %d: %s\n",++cas,ans); }
}
}