HDU3446 传送门
感觉有必要说一下题意,这个地方读了好久没搞清楚要做什么。
给定一个棋盘,有空地和墙两种方块
(假如棋子在中间红色点的情况)棋子只能往图中规定的
20
20
20个黑点跳过去(黑点不能是墙,保证初始位置不是墙)
分析
将所有除了
k
i
n
g
king
king 点,能够联通的点互相连边
假如除去了
k
i
n
g
king
king 所在的位置的最大匹配为
x
x
x,此时最大匹配的意义为,
现在把 k i n g king king点 加入进去,如果能够再找到一个点匹配,说明存在一条以 k i n g king king为起点的增广路,且 k i n g king king点一定在最大匹配里面,顺着这条增广路走,后者只能被动走到匹配边的另一头(匹配点)
结论:只要 k i n g king king一定在最大匹配里面,就一定先手必胜!
代码
//HDU3446
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int caz = 0;
int dir[][2] = {2, 2, 2, 1, 2, -1, 2, -2, 1, 2, 1, 1, 1, 0, 1, -1, 1, -2, 0, 1, 0, -1, -1, 2, -1, 1, -1, 0, -1, -1, -1, -2, -2, 2, -2, 1, -2, -1, -2, -2};
int head[MAX_N];
int tot = 0;
struct Edge {
int to, nxt;
}edge[MAX_N];
void addEdge(int u, int v) {
edge[tot].nxt = head[u];
edge[tot].to = v;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
head[v] = tot++;
}
int father[MAX_N];
int match[MAX_N];
int vis[MAX_N];
int pre[MAX_N];
int tim = 0;
int dfn[MAX_N];
queue<int>Q;
int find(int x) {
return x==father[x] ? x : father[x] = find(father[x]);
}
int LCA(int x, int y) {
++tim;
x = find(x);
y = find(y);
while (dfn[x] != tim) {
dfn[x] = tim;
x = find(pre[match[x]]);
if (y) swap(x, y);
}
return x;
}
void fix(int x) {
int nxt = 0;
while (x) {
nxt = match[pre[x]];
match[x] = pre[x];
match[pre[x]] = x;
x = nxt;
}
}
void blossom(int x, int y, int lca) {
while (find(x) != lca) {
pre[x] = y;
y = match[x];
if (vis[y]==2) vis[y] = 1, Q.push(y);
if (x == find(x)) father[x] = lca;
if (y == find(y)) father[y] = lca;
x = pre[y];
}
}
bool aug(int u) {
while (Q.size()) Q.pop();
for (int i = 1; i <= K; ++i) {
father[i] = i;
pre[i] = vis[i] = 0;
}
Q.push(u);
vis[u] = 1;
int v;
while (Q.size()) {
u = Q.front();Q.pop();
for (int i = head[u];~i;i=edge[i].nxt) {
if (vis[v=edge[i].to] == 2 || find(u) == find(v)) continue;
if (!vis[v]) {
pre[v] = u;
vis[v] = 2;
if (!match[v]) {
fix(v);
return true;
}
vis[match[v]] = 1;
Q.push(match[v]);
} else {
int lca = LCA(u, v);
blossom(u, v, lca);
blossom(v, u, lca);
}
}
}
return false;
}
void init() {
memset(head, -1, sizeof head);
memset(match, 0, sizeof match);
tot = 0;
}
struct Node {
int x, y;
}arr[MAX_N];
bool check(int x, int y) {
for (int i = 0; i < 20; ++i) {
if (arr[x].x + dir[i][0] == arr[y].x && arr[x].y + dir[i][1] == arr[y].y) {
return true;
}
}
return false;
}
void solve(){
init();
cin >> N >> M;
Node king;
char c;
K = 0;
for (int i = 1; i <= N; ++i) {
getchar();
for (int j = 1; j <= M; ++j) {
c = getchar();
if (c == 'K') {
king.x = i;
king.y = j;
} else if (c == '.') {
arr[++K].x = i;
arr[K].y = j;
}
}
}
for (int i = 1; i <= K; ++i) {
for (int j = i+1; j <= K; ++j) {
if (check(i, j)) {
addEdge(i, j);
}
}
}
int ans = 0;
for (int i = 1; i <= K; ++i) {
if (!match[i]) ans += aug(i);
}
arr[++K] = king;
for (int i = 1; i < K; ++i) {
if (check(i, K)) {
addEdge(i, K);
}
}
pr("Case #%lld: ", ++caz);
if (aug(K)) {
puts("daizhenyang win");
} else {
puts("daizhenyang lose");
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;cin >> T;
while (T--) solve();
return AC;
}