文章目录
ICPC2016大连
A.Wrestling Match
题意: 给定n个人,这些人可能是好人也可能是坏人,要求好人和坏人才能连边,问是否能够把每个人标记为好人或者坏人
题解: 本题是二分图染色问题。首先需要判断下孤立点,如果是孤立点同时没有染色,那么输出no。然后先把存在染色的连通块染色法判断下,之后再对不存在染色点的连通块再次染色法判断下。不能直接一次dfs染色,因为子节点虽然现在没有被染色,但是可能子节点的颜色是固定的,因此可能会染色错误。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
using namespace std;
int const N = 1e4 + 10, M = 2e4 + 10;
typedef long long LL;
typedef pair<int, int> PII;
int n, m, T, k1, k2;
int e[M], ne[M], h[N], color[N], idx, vis[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dfs(int u, int c) {
color[u] = c; // 给u号点打上c的颜色
for (int i = h[u]; i != -1; i = ne[i]) {
// 遍历所有与i号点相连的点
int j = e[i]; // 看j号点
if (!color[j]) {
// 如果j号点没有染色
if (!dfs(j, 3 - c)) return 0; // 如果j号点染色3-c过程中失败
}
if (color[j] == c) return 0; // 如果j号点也染色c颜色
}
return 1; // 如果u号点的所有邻点都没有染色失败
}
int main() {
while(scanf("%d%d%d%d", &n, &m, &k1, &k2) != EOF) {
memset(h, -1, sizeof h);
memset(color, 0, sizeof color);
memset(vis, 0, sizeof vis);
idx = 0;
for (int i = 1; i <= m; ++i) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
vis[a] = vis[b] = 1;
}
for (int i = 1; i <= k1; ++i) {
int u;
scanf("%d", &u);
color[u] = 1;
}
for (int i = 1; i <= k2; ++i) {
int u ;
scanf("%d", &u);
color[u] = 2;
}
int flg = 1;
for (int i = 1; i <= n; ++i)
if (!vis[i] && !color[i]) {
flg = 0;
printf("NO\n");
break;
}
if (!flg) continue;
for (int i = 1; i <= n; ++i) {
if (color[i]) {
if (!dfs(i, color[i])) {
// 如果i号点染色失败
flg = 0; // flg 打上失败标记
printf("NO\n");
break;
}
}
}
if (!flg) continue;
for (int i = 1; i <= n; ++i) {
// 从1号点开始枚举
if (color[i]) continue;
if (!dfs(i, 1)) {
// 如果i号点染色失败
flg = 0; // flg 打上失败标记
break;
}
}
if (flg) printf("YES\n");
else printf("NO\n");
}
return 0;
}
C.Game of Taking Stones
题意: 有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。
题解: 威佐夫博弈模板题,套个java高精度即可。
代码:
import java