题目大意:有n个人对m个方案投票,每个人最多只能对其中的4个方案投票(其他的相当于弃权),每一票要么支持要么反对。问是否存在一个最终决定,使得每个投票人都有超过一半的建议被采纳,在所有可能的最终决定中,哪些方案的态度是确定的
解题思路:参考了一下别人的思路,学习了
当想要确定某一个状态(i)时,可以用他的相反状态(i^1)和该状态建立一条边,那样的话,每当dfs到他的相反状态时,就会return false
在理解了上面的基础上,就可以建边了
首先,要有超过一半的投票被采纳。也就是说,当投票数小于等于2的时候,每一票都要被采纳,当投票数大于2时,只能有一票被否定,依此建边
接着就是判断能否被采纳了,可以枚举每个方案的最终决定,如果有一个方案无论是被否定还是被肯定都是错的话,那么就不可能满足所有人的要求了(超过一半的建议被采纳),可以在枚举的时候边记录最终状态的态度
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define N 110
#define M 1010
struct vote{
int bill, vote;
}V[M][5];
vector<int> G[M];
int ans[N];
int n, m;
bool mark[N * 2];
void AddEdge(int x, int valx, int y, int valy) {
x = x * 2 + valx;
y = y * 2 + valy;
G[x].push_back(y);
}
void init() {
for (int i = 0; i < 2 * n; i++)
G[i].clear();
int t;
char c;
for (int i = 0; i < m; i++) {
scanf("%d", &t);
for (int j = 0; j < t; j++) {
scanf("%d %c", &V[i][j].bill, &c);
V[i][j].bill--;
if (c == ‘y‘)
V[i][j].vote = 1;
else
V[i][j].vote = 0;
}
if (t <= 2) {
for (int j = 0; j < t; j++)
AddEdge(V[i][j].bill, V[i][j].vote ^ 1, V[i][j].bill, V[i][j].vote);
}
else {
for (int j = 0; j < t; j++)
for (int k = 0; k < t; k++) {
if (j == k)
continue;
AddEdge(V[i][j].bill, V[i][j].vote ^ 1, V[i][k].bill, V[i][k].vote);
}
}
}
}
int S[M];
int c;
bool dfs(int u) {
if (mark[u ^ 1])
return false;
if (mark[u])
return true;
mark[u] = true;
S[++c] = u;
for (int i = 0; i < G[u].size(); i++)
if (!dfs(G[u][i]))
return false;
return true;
}
bool TwoAST() {
for (int i = 0; i < 2 * n; i += 2) {
if (!mark[i] && !mark[i ^ 1]) {
c = 0;
if (!dfs(i)) {
while (c)
mark[S[c--]] = false;
if (!dfs(i ^ 1))
return false;
}
}
}
return true;
}
int cas = 1;
void solve() {
int i;
for (i = 0; i < n; i++) {
int tmp = 0;
memset(mark, 0, sizeof(mark));
//第i个方案被否定时
AddEdge(i, 1, i, 0);
if (TwoAST())
tmp += 1;
G[(i << 1) ^ 1].pop_back();
//第i个方案被肯定时
memset(mark, 0, sizeof(mark));
AddEdge(i, 0, i, 1);
if (TwoAST())
tmp += 2;
G[(i << 1)].pop_back();
if (tmp == 0)
break;
else if(tmp == 1)
ans[i] = 0;
else if (tmp == 2)
ans[i] = 1;
else if (tmp == 3)
ans[i] = 2;
}
printf("Case %d: ", cas++);
if (i != n) {
printf("impossible\n");
return ;
}
for (int i = 0; i < n; i++) {
if (!ans[i])
printf("n");
else if(ans[i] == 1)
printf("y");
else if(ans[i] == 2)
printf("?");
}
printf("\n");
}
int main() {
while (scanf("%d%d", &n, &m) != EOF && n + m) {
init();
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
UVALive - 4452 The Ministers' Major Mess(2-SAT)
时间: 2024-10-11 01:24:30