2-sat。又学到了一种使用的方法:当确定选择某中状态A时,从它的对立状态A^1引一条边add(A^1,A),从而使凡是dfs经过对立状态,必然return false;即保证若存在一种可能性,必然是经过该状态A的。
题意:m个人对n个方案投票,每人之多投4票,是否存在一种方案使每个人所投的一半以上的票被采纳。依次输出每个议题最终的结果。
1、注意是一半以上,我一开始理解成一半,结果无法根据必然性建边。<=2票则都被采纳,<=4票则至多有一票不被采纳。
2、输出时要注意,因为每个议题的结果都不一定相同,所以需要一一判断。需要分别进行solve(i),和solve(i+1)。这里一开始我直接是把solve()函数中的dfs(i)和dfs(i+1)分开,wa了,后来考虑发现,solve()一次,是对遍历整个方案寻找可行性;而dfs()只是对一个连通的量做了标记。
注意:分别检查同一个议题的两种状态,确定从状态A经过,add(A^1,A),结束要记得G[i].pop_back();
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 7 const int MAXN=555; 8 9 struct Vote{ 10 int v,c; 11 }vote[MAXN][5]; 12 13 bool mark[MAXN<<1]; 14 int res[MAXN]; 15 int s[MAXN<<1],c; 16 vector<int >G[MAXN<<1]; 17 18 void init(int n) 19 { 20 for(int i=0;i<(n<<1);i++) 21 G[i].clear(); 22 memset(mark,0,sizeof(mark)); 23 } 24 25 void add(int x,int dx,int y,int dy) 26 { 27 x=(x<<1)+dx; 28 y=(y<<1)+dy; 29 G[x].push_back(y); 30 } 31 32 bool dfs(int x) 33 { 34 if(mark[x^1]) 35 return false; 36 if(mark[x]) 37 return true; 38 s[c++]=x; 39 mark[x]=true; 40 for(int i=0;i<G[x].size();i++) 41 if(!dfs(G[x][i])) 42 return false; 43 return true; 44 } 45 46 bool solve(int n) 47 { 48 for(int i=0;i<(n<<1);i+=2) 49 { 50 if(!mark[i]&&!mark[i+1]){ 51 c=0; 52 if(!dfs(i)){ 53 while(c>0) 54 mark[s[--c]]=false; 55 if(!dfs(i+1)) 56 return false; 57 } 58 } 59 } 60 return true; 61 } 62 63 bool test(int n) 64 { 65 for(int i=0;i<n;i++) 66 { 67 int ans=0; 68 memset(mark,0,sizeof(mark)); 69 add(i,1,i,0); 70 while(c>0) 71 mark[s[--c]]=false; 72 if(solve(n)) 73 ans+=1; 74 G[(i<<1)+1].pop_back(); 75 76 memset(mark,0,sizeof(mark)); 77 add(i,0,i,1); 78 while(c>0) 79 mark[s[--c]]=false; 80 if(solve(n)) 81 ans+=2; 82 G[i*2].pop_back(); 83 84 if(ans==0) 85 return false; 86 else if(ans==1) 87 res[i]=-1; 88 else if(ans==2) 89 res[i]=1; 90 else if(ans==3) 91 res[i]=0; 92 } 93 return true; 94 } 95 96 int main() 97 { 98 int n,m; 99 int cnt=0,ans; 100 while(~scanf("%d%d",&n,&m)) 101 { 102 if(!n&&!m) 103 return 0; 104 105 init(n); //!! 106 for(int i=0;i<m;i++) 107 { 108 scanf("%d",&ans); 109 110 for(int j=0;j<ans;j++) 111 { 112 int x; 113 char ch[2]; 114 scanf("%d %s",&x,ch); 115 vote[i][j].v=--x; 116 if(ch[0]=='y') 117 vote[i][j].c=1; 118 else 119 vote[i][j].c=0; 120 } 121 if(ans<=2){ 122 for(int j=0;j<ans;j++) 123 add(vote[i][j].v,vote[i][j].c^1,vote[i][j].v,vote[i][j].c); 124 }else 125 for(int j=0;j<ans;j++) 126 for(int k=0;k<ans;k++) 127 { 128 if(j==k) 129 continue; 130 add(vote[i][j].v,vote[i][j].c^1,vote[i][k].v,vote[i][k].c); 131 } 132 } 133 134 memset(res,0,sizeof(res)); 135 printf("Case %d: ",++cnt); 136 if(!test(n)) 137 printf("impossible "); 138 else { 139 for(int i=0;i<n;i++) 140 { 141 if(res[i]==0) 142 printf("?"); 143 else if(res[i]==1) 144 printf("y"); 145 else if(res[i]==-1) 146 printf("n"); 147 } 148 printf(" "); 149 } 150 } 151 return 0; 152 } 153 /* 154 5 3 155 2 1 y 2 n 156 3 1 y 3 n 4 y 157 4 1 n 3 n 4 n 5 y 158 */