题目链接:
题目大意:
有n个人对m个方案投票,每个人最多只能对其中的4个方案投票(少投的票相当于弃权),每一票要么支持要么反对。问是否存在一个最终决定,使得每个投票人都有超过一半的投票被采纳,在所有可能的最终决定中,哪些方案的状态是确定的。
题解:
每个方案只有实施和不实施两种状态,想到2-sat。
每个人的投票相当于约束条件。因为每个人都要有超过一半的投票被采纳,如果他只投了投了2票及以下,那么他的投票就应该全部被采纳;如果他投了3票或者4票,他最多只有一票没有被采纳,也就是说他投的票中两两之间必有一票被采纳。
判断哪些方案是确定的,可以依次对每个方案分别取真与假再跑一边2-sat判断能否成立。
关于 2-SAT(tarjan求法)
代码:
#include <bits/stdc++.h>
#define LL long long
#define LD long double
#define ULL unsigned long long
#define UI unsigned int
#define PII pair<int,int>
#define MPII(x,y) pair<int,int>{x,y}
#define _for(i,j,k) for(int i=j;i<=k;i++)
#define for_(i,j,k) for(int i=j;i>=k;i--)
#define efor(i,u) for(int i=head[u];i;i=net[i])
#define lowbit(x) (x&-x)
#define ls(x) x<<1
#define rs(x) x<<1|1
#define inf 0x3fffffff
//#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
const int maxn = 2e4 + 5;
const int M = 1e9 + 7;
inline int mad(int a,int b){return (a+=b)>=M?a-M:a;}
//2-SAT板子
struct TwoSAT{ //2*i+1为真,2*i为假
int n;
vector<int> G[maxn*2];
bool mark[maxn*2];
int S[maxn*2],c;
bool dfs(int x){
if(mark[x^1]) return false;
if(mark[x]) return true;
mark[x]=true;
S[c++]=x;
for(int i=0;i<(int)G[x].size();i++)
if(!dfs(G[x][i])) return false;
return true;
}
void dfs_fix(int x){
mark[x]=true;
for(auto y:G[x]){
if(!mark[y]) dfs_fix(y);
}
}
void init(int n){
this->n=n;
for(int i=0;i<n*2;i++) G[i].clear();
memset(mark,0,sizeof(mark));
}
void clear(){
memset(mark,0,sizeof(mark));
}
void add_clause(int x,int xval,int y,int yval){ //条件 x为xval或者y为yval
x = (x<<1)|xval;
y = (y<<1)|yval;
G[x^1].push_back(y);
G[y^1].push_back(x);
}
void add_fixed(int x,int val){ //x恒为val
x = (x<<1)|val;
dfs_fix(x);
}
bool solve(){
for(int i=0;i<n*2;i+=2){
if(mark[i] && mark[i+1]) return false;
if(!mark[i]&&!mark[i+1]){
c=0;
if(!dfs(i)){
while(c>0) mark[S[--c]]=false;
if(!dfs(i+1)) return false;
}
}
}
return true;
}
};
TwoSAT sat;
int p[5],c[5],mustbe[maxn];
string an;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m,k,kase=0;char ch;
while(cin>>n>>m,n|m){
an.clear();
sat.init(2*n);
_for(i,0,n) mustbe[i]=-1;
_for(i,1,m){
cin>>k;
_for(j,1,k){
cin>>p[j]>>ch;
c[j]= ch=='n'?0:1;
}
if(k>=3)
_for(j,1,k){
_for(d,j+1,k){
sat.add_clause(p[j]-1,c[j],p[d]-1,c[d]);
}
}
else{
_for(j,1,k){
sat.add_fixed(p[j]-1,c[j]);
mustbe[p[j]-1]=c[j];
}
}
}
cout<<"Case "<<++kase<<": ";
if(sat.solve()){
for(i,0,n-1){
if(mustbe[i]==-1){
sat.clear();
_for(j,0,n-1){
if(mustbe[j]!=-1) sat.add_fixed(j,mustbe[j]);
}
sat.add_fixed(i,0);
if(!sat.solve()){
an+='y';continue;
}
sat.clear();
_for(j,0,n-1){
if(mustbe[j]!=-1) sat.add_fixed(j,mustbe[j]);
}
sat.add_fixed(i,1);
if(!sat.solve()){
an+='n';continue;
}
an+='?';
}
else{
an += (mustbe[i]?'y':'n');
}
}
cout<<an<<"\n";
}
else{
cout<<"impossible\n";
}
}
return 0;
}
```cpp