題目鏈接:
題目大意:
有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