HDU3446 daizhenyang‘s chess【带花树】

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据提供的引用内容,HDU1622是一道关于二叉树的题目,要求读入一系列二叉树的节点信息,输出它们的层序遍历结果。如果输入的二叉树不完整或存在重复节点,则输出"not complete"。下面是Java的实现代码: ```java import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class Main { static class Node { int val; Node left, right; public Node(int val) { this.val = val; } } public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s = sc.nextLine(); if (s.isEmpty()) { continue; } String[] nodes = s.split("\\s+"); Node root = new Node(Integer.parseInt(nodes[0].substring(1))); Queue<Node> queue = new LinkedList<>(); queue.offer(root); boolean isComplete = true; for (int i = 1; i < nodes.length - 1; i += 2) { Node cur = queue.poll(); if (!nodes[i].equals("()")) { cur.left = new Node(Integer.parseInt(nodes[i].substring(1))); queue.offer(cur.left); } else { isComplete = false; } if (!nodes[i + 1].equals("()")) { cur.right = new Node(Integer.parseInt(nodes[i + 1].substring(0, nodes[i + 1].length() - 1))); queue.offer(cur.right); } else { isComplete = false; } } if (!isComplete) { System.out.println("not complete"); continue; } StringBuilder sb = new StringBuilder(); queue.offer(root); while (!queue.isEmpty()) { Node cur = queue.poll(); sb.append(cur.val).append(" "); if (cur.left != null) { queue.offer(cur.left); } if (cur.right != null) { queue.offer(cur.right); } } System.out.println(sb.toString().trim()); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hexrt

客官,请不要给我小费!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值