题目大意:N张票,M个人,每张票的形式如下
土i 土j,如果是+,表示要求留下,如果是-,表示要求离开
问能否满足每张票的其中一个要求,如果可以,输出多少个人留下,并按升序输出留下的人
解题思路:2-SAT的模版题,这里只是验证一下模版
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAXNODE = 10010 * 2;
struct TwoSat{
int n, top;
vector<int> G[MAXNODE];
bool mark[MAXNODE];
int Stack[MAXNODE];
void init(int n) {
this->n = n;
for (int i = 0; i < 2 * n; i++)
G[i].clear();
memset(mark, 0, sizeof(mark));
}
//x = xval或者y = yval
void AddClause(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 dfs(int u) {
//当前需要标记的结点是u,如果u ^ 1这个结点已经被标记过了,就表示两个结点都要被标记掉,明显冲突了
if (mark[u ^ 1]) return false;
if (mark[u]) return true;
mark[u] = true;
//模拟栈
Stack[++top] = u;
//和u相邻的点都进行标记,以判断是否出错
for (int i = 0; i < G[u].size(); i++)
if (!dfs(G[u][i])) return false;
return true;
}
bool solve() {
for (int i = 0; i < 2 * n; i += 2)
//如果在其他点的标志过程中,其中一个点被标记了,就无需在枚举了,因为在dfs的过程中,和其相连的点也被标记了,较少了重复枚举
if (!mark[i] && !mark[i ^ 1]) {
top = 0;
//假设xi为假是错误的,这时候就要进行回溯,将dfs过程中标记过的点还原,再判断对错
if (!dfs(i)) {
while (top) mark[Stack[top--]] = false;
if (!dfs(i ^ 1)) return false;
}
}
return true;
}
}Two;
int n, m, cas = 1;
void solve() {
scanf("%d%d", &n, &m);
Two.init(m);
char vote1[10], vote2[10];
int x, xval, y, yval, len;
for (int i = 0; i < n; i++) {
scanf("%s%s", vote1, vote2);
len = strlen(vote1);
if (vote1[0] == '+') xval = 0;
else xval = 1;
x = 0;
for (int j = 1; j < len; j++)
x = x * 10 + vote1[j] - '0';
len = strlen(vote2);
if (vote2[0] == '+') yval = 0;
else yval = 1;
y = 0;
for (int j = 1; j < len; j++)
y = y * 10 + vote2[j] - '0';
Two.AddClause(x - 1, xval, y - 1, yval);
}
if (!Two.solve())
printf("Case %d: No\n", cas++);
else {
vector<int> members;
int ans = 0;
for (int i = 0; i < 2 * m; i += 2) {
if (Two.mark[i]) {
ans++;
members.push_back(i / 2 + 1);
}
}
if (ans == 0) printf("Case %d: Yes\n0\n", cas++);
else {
printf("Case %d: Yes\n", cas++);
printf("%d", ans);
for (int j = 0; j < members.size(); j++)
printf(" %d", members[j]);
printf("\n");
}
}
}
int main() {
int test;
scanf("%d", &test);
while (test--) solve();
return 0;
}