csdn真是神坑,剛寫的解題竟然被吞了,尼瑪,害我重寫。
本題的突破口在每個投票人都要有超過一半的建議被採納。所以對於k<3的,每個建議都得採納,k>=3的,只有一個建議不能採納。
都得採納的,我用了一個must數組記錄,然後dfs找出所有開始就定下來的建議的值;只有一個不能採納,即每兩個建議間都至少有一個被採納。
最後輸出要判斷“?”,我的方法是對每個建議檢查是否無論它采不採納都有解。開始忘了dfs找所有應該must的建議,2y
#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<algorithm>using namespace std;const int maxn = 100 + 5;struct TwoSAT { int n; vector<int> G[maxn*2]; bool mark[maxn*2],must[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 < G[x].size(); i++) if (!dfs(G[x][i])) return false; return true; } void dfs2(int x){ must[x] = true; for(int i = 0;i < G[x].size();i++) if(!must[G[x][i]]) dfs2(G[x][i]); } void init(int n) { this->n = n; for (int i = 0; i < n*2; i++) G[i].clear(); memset(mark, 0, sizeof(mark)); memset(must,0,sizeof(must)); } void clear(){ memset(mark,0,sizeof(mark)); for(int i = 0;i < 2*n;i++) mark[i] = must[i];//每次都要重新對mark賦值 } // x = xval or y = yval void add_clause(int x, int xval, int y, int yval) { x = x * 2 + xval; y = y * 2 + yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i = 0; i < n*2; i += 2){ if(mark[i] && mark[i+1]) return false;//對於開始就有對mark標記的,這句話是必須的 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 solver;int tag[maxn];int main(){ int n,m,kase=0; while(scanf("%d%d",&m,&n)){ if(n == 0 && m == 0) break; solver.init(m); memset(tag,0,sizeof(tag)); while(n--){ int c,x[10],valx,valy; char s[10][10]; scanf("%d",&c); for(int i = 0;i < c;i++) scanf("%d%s",&x[i],s[i]); if(c >= 3){ for(int i = 0;i < c;i++) for(int j = i+1;j < c;j++){ valx = s[i][0]=='y'?1:0; valy = s[j][0]=='y'?1:0; solver.add_clause(x[i]-1,valx,x[j]-1,valy); } } else{ for(int i = 0;i < c;i++){ valx = s[i][0]=='y'?1:0; solver.must[2*(x[i]-1)+valx] = 1; } } } for(int i = 0;i < 2*m;i++) if(solver.must[i]) solver.dfs2(i); for(int i = 0;i < m;i++){ if(solver.must[2*i] || solver.must[2*i+1]) continue; solver.clear(); solver.mark[2*i] = true; bool tag1 = solver.solve(); solver.clear(); solver.mark[2*i+1] = true; bool tag2 = solver.solve(); if(tag1 && tag2) tag[i] = 1; } solver.clear(); printf("Case %d: ",++kase); if(!solver.solve()) printf("impossible\n"); else{ for(int i = 0;i < m;i++){ if(tag[i]) printf("?"); else if(solver.mark[2*i]) printf("n"); else printf("y"); } printf("\n"); } } return 0;}