hdoj 4753 博弈+搜索

hdoj 4753

题意:给一个九宫格涂边,每次涂的边长为1,如果涂的这条边可以组成p个边长为1的正方形,就加p分,现在Tom和Jerry已经走了若干步,问接下来若两人用最优策略,谁会赢。

思路:刚开始没仔细读题以为就是个简单的模拟。。。没想到是个博弈,但是博弈题我没怎么做过啊。。

首先要了解必胜态和必败态的概念,在一棵博弈树上,如果该步是叶子节点,那么根据条件分高的就获胜,是必胜态,反之就是必败态;如果不是叶子节点,那么如果该节点的子节点中有必败态,那么该节点就是必胜态,反之就是必败态(因为接下来一步是对手的回合,无论哪步对手都会赢的话那自己这一步肯定会输)。

所以问题就是判断当前这一步是必败态还是必胜态。

搜索时用dfs搜到叶子节点进行回溯,如果子节点是必胜态,就接着搜其他子节点,如果都是必胜态,那么该节点就是必败态;如果子节点有必败态,那么该节点一定是必胜态,直接回溯。

注意判断当前是谁的回合,这个节点的状态是谁的状态。

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
bool vis[20][20];
int Tom200, Jerry404;
int getpoints(int a, int b){
    int ret = 0;
    if(b - a > 1){
        if(a % 4 != 1)
            if(vis[a - 1][b - 1] && vis[a][a - 1] && vis[b][b - 1]) ret++;
        if(a % 4 != 0)
            if(vis[a + 1][b + 1] && vis[a][a + 1] && vis[b][b + 1]) ret++;
    }
    else {
        if(a > 4)
            if(vis[a - 4][b - 4] && vis[a][a - 4] && vis[b][b - 4]) ret++;
        if(a < 13)
            if(vis[a + 4][b + 4] && vis[a][a + 4] && vis[b][b + 4]) ret++;
    }
    return ret;
}
vector<pair<int, int> > vct;
bool dfs(int score, bool tomTurn){
    bool done = false;
    for(int i = 0; i < vct.size(); i++) {
        if(!vis[vct[i].first][vct[i].second]){
            done = true;
            vis[vct[i].first][vct[i].second] = vis[vct[i].second][vct[i].first] = true;
            int p = getpoints(vct[i].first, vct[i].second);
            if(!tomTurn) p = -p;
            bool win = !dfs(score + p, !tomTurn);
            vis[vct[i].first][vct[i].second] = vis[vct[i].second][vct[i].first] = false;
            if(win) return true;
        }
    }
    if(!done) return score > 0;
    return false;
}
main() {
    int cnt = 0;
    int t, n;
    scanf("%d", &t);
    for(int cas = 1; cas <= t; cas++) {
        memset(vis, 0, sizeof vis);
        vct.clear();
        Tom200 = Jerry404 = 0;
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            int a, b;
            scanf("%d %d", &a, &b);
            vis[a][b] = vis[b][a] = true;
            if(a > b){
                a = a ^ b;
                b = a ^ b;
                a = a ^ b;
            }
            if(i % 2) Jerry404 += getpoints(a, b);
            else Tom200 += getpoints(a, b);
        }
        for(int i = 1; i < 16; i++) if((i % 4) >= 1 && !vis[i][i + 1]) vct.push_back(make_pair(i, i + 1));
        for(int i = 1; i <= 12; i++) if(!vis[i][i + 4]) vct.push_back(make_pair(i, i + 4));
        printf("Case #%d: ", cas);
        bool win;
        if(n % 2) win = !dfs(Tom200 - Jerry404, false);
        else win = dfs(Tom200 - Jerry404, true);
        puts(win ? "Tom200" : "Jerry404");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值