HDU3446 daizhenyang‘s chess【带花树】

126 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

HDU3446 传送门 感觉有必要说一下题意,这个地方读了好久没搞清楚要做什么。 给定一个棋盘,有空地和墙两种方块 (假如棋子在中间红色点的情况)棋子只能往图中规定的 2020个黑点跳过去(黑点不能是墙,保证初始位置不是墙) 在这里插入图片描述

分析

将所有除了 kingking 点,能够联通的点互相连边 假如除去了 kingking 所在的位置的最大匹配为 xx,此时最大匹配的意义为,

现在把 kingking点 加入进去,如果能够再找到一个点匹配,说明存在一条以kingking为起点的增广路,且kingking一定在最大匹配里面,顺着这条增广路走,后者只能被动走到匹配边的另一头(匹配点)

结论:只要kingking一定在最大匹配里面,就一定先手必胜!

代码

//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;
}