1. 程式人生 > 實用技巧 >HDU-6850 Game

HDU-6850 Game


title: HDU-6850 Game
date: 2020-08-12 20:00:00
categories:

  • 博弈論
    tags:
  • 記憶化搜尋

HDU-6850 \(Game\)

題目連結 http://acm.hdu.edu.cn/showproblem.php?pid=6850

如果感覺不適請前往 [https://vagrantac.info/2020/08/12/杭電多校/HDU6850 Game/](https://vagrantac.info/2020/08/12/杭電多校/HDU6850 Game/)

題解

我使用的是標程的第二種解法,和當時在訓練的想法是一樣的,

首先簡述一下我的想法,

以下直接忽略一個點不能走多次

使用陣列 \(dp[x][y]\)

表示當前位置為 \(x\) 點,上一步為 \(y\) 點狀態,\(0\) 表示必敗態,\(1\) 表示必勝態。

也可以將 \(x\)\(y\) 看作是一條邊, \(0\) 表示走 \(x\)\(y\) 這條邊為必敗態,否則為必勝態。

之後使用記憶化搜尋進行搜尋一下,

如果一條邊 \(x\)\(y\)\(y\) 下一步沒有點可走的話表示這個狀態為必敗態。

對於一個狀態,如果它的下一個可以到達的所有的狀態中存在必敗態,\(namo\) 這個狀態為必勝態,

否則為必敗態。(關於必勝態和必敗態,詳細可以看一下博弈論)


下面是證明一下

這個題我上面的解法會有一個問題,就是出現環怎麼辦。

環的話,分類考慮一下就好了

如果 \(dp[x][y]\) 存在下一步狀態並且存在 \(z\) 使得 \(dp[y][z] = 0\) ,那直接走這條邊就好了,不需要考慮其他邊,並且保證了必勝態了。

否則的話對於所有的 \(z\) 保證 \(dp[y][z] = 1\) ,那到達這個位置的時候註定了必敗態了。

這個問題證明很簡單,當然也是我第一次手推證明,之前的都是盲猜和結論題,推就完事了。

程式碼

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 2e3+55;
typedef long long ll;
ll cost[M][M];
int dp[M][M];
ll x[M], y[M];
int n;
int dfs(int xx, int yy) {
    if (dp[xx][yy] != -1) return dp[xx][yy];
    int b = 0;
    for (int i = 0; i < n; ++ i) {
        if (i == yy) continue;
        if (cost[yy][i] > cost[xx][yy]) {
            if (dfs(yy, i) == 0) {
                dp[xx][yy] = 1;
                return 1;
            }
            else b ++;
        }
    }
    dp[xx][yy] = 0;
    return dp[xx][yy];
}
int main() {
    int t;
    scanf("%d", &t);
    while (t --) {
        scanf("%d", &n);
        for (int i = 0; i < n; ++ i) {
            scanf("%lld%lld", &x[i], &y[i]);
        }
        for (int i = 0; i < n; ++ i) {
            for (int j = 0; j < n; ++ j) {
                cost[i][j] = (x[i]-x[j]) * (x[i]-x[j]) + (y[i]-y[j]) * (y[i]-y[j]);
                dp[i][j] = -1;
            }
        }
        int a = 0, b = 0;
        for (int i = 1; i < n; ++ i) {
            if (dfs(0, i) == 0) {
                a ++;
                break;
            } 
            else b ++;
        }
        if (a) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}