题目大意:有两个人玩剪刀石头布,已经知道A的所有出法,A为了赢,给B设置了M种限制,限制为a,b,c
如果c == 1,那么B第a回合和第b回合的出法要不同
如果c == 0,那么B第a回合和第b回合的出法要相同
如果B能一回合都不输,且遵循M种限制,那么B就赢了,问B最后能否能赢
解题思路:要不输的话,那么就只能平局或者赢了,先预处理每回合的出法
接着处理限制条件,如果限制条件c == 1,且有出法相同的情况,那么就连边,连向另一种出法
如果c == 0,且有出法不同的情况,那么就连边,连向另一种出法
好难表达,语言表达能力不够。。。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 20010
vector<int> G[N];
bool mark[N];
int S[N], can1[N], can2[N];
int top, n, m;
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() {
scanf("%d%d", &n, &m);
int t;
for (int i = 0; i < n; i++) {
scanf("%d", &can1[i]);
can1[i]--;
can2[i] = (can1[i] + 1) % 3;
}
for (int i = 0; i < 2 * n; i++)
G[i].clear();
int A, B, K;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &A, &B, &K);
A--; B--;
//要求出法不同
if (K == 1) {
if (can1[A] == can1[B])
AddEdge(A, 0, B, 1), AddEdge(B, 0, A, 1);
if (can1[A] == can2[B])
AddEdge(A, 0, B, 0), AddEdge(B, 1, A, 1);
if (can2[A] == can1[B])
AddEdge(A, 1, B, 1), AddEdge(B, 0, A, 0);
if (can2[A] == can2[B])
AddEdge(A, 1, B, 0), AddEdge(B, 1, A, 0);
}
//要求出法相同
if (K == 0) {
if (can1[A] != can1[B])
AddEdge(A, 0, B, 1), AddEdge(B, 0, A, 1);
if (can1[A] != can2[B])
AddEdge(A, 0, B, 0), AddEdge(B, 1, A, 1);
if (can2[A] != can1[B])
AddEdge(A, 1, B, 1), AddEdge(B, 0, A, 0);
if (can2[A] != can2[B])
AddEdge(A, 1, B, 0), AddEdge(B, 1, A, 0);
}
}
}
bool dfs(int u) {
if (mark[u ^ 1])
return false;
if (mark[u])
return true;
mark[u] = true;
S[++top] = u;
for (int i = 0; i < G[u].size(); i++)
if (!dfs(G[u][i]))
return false;
return true;
}
bool solve() {
memset(mark, 0, sizeof(mark));
for (int i = 0; i < 2 * n; i += 2) {
if (!mark[i] && !mark[i ^ 1]) {
top = 0;
if (!dfs(i)) {
while (top) mark[S[top--]] = false;
if (!dfs(i ^ 1))
return false;
}
}
}
return true;
}
int main() {
int test, cas = 1;
scanf("%d", &test);
while (test--) {
init();
printf("Case #%d: %s\n", cas++, solve() ? "yes": "no");
}
return 0;
}