Luogu P4363 [九省联考2018]一双木棋chess

组合游戏

当一个游戏满足如下几个性质:
1.每个人都足够聪明
2.游戏可以化归到有向无环图上
3.游戏的内容是确定的
则称这个游戏是组合游戏

Solution

该题中的游戏很明显是个组合游戏,另外题目中有条件“菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大”,如果菲菲的贡献为正,牛牛的贡献为负,也就是说一个人希望总贡献最大,另一个人希望总贡献最小,对抗搜索就好了。

Code:

//直接用map存了状态,吸氧才过了
#include <bits/stdc++.h>

using namespace std;

const int MAXN = 20;

int n,m;

struct State{
    int num[MAXN];
    bool operator < (const State &x)const{
        for (int i = 1; i <= n; i++) {
            if (num[i] != x.num[i]) return num[i] < x.num[i];
        }
        return false;
    }
};

map<State,int> dp1,dp2;

int a[MAXN][MAXN],b[MAXN][MAXN];

int DFS2(State s);

int DFS1(State s) {
    if (dp1.find(s) != dp1.end()) return dp1[s];
    int ret =  -1e9;
    for (int i = 1; i <= n; i++) {
        if (i == n && s.num[n] == m - 1 && s.num[n - 1] == m) return a[n][m];
        if (s.num[i] < m && (i == 1 || s.num[i] < s.num[i - 1])) {
            s.num[i]++;
            ret = max(ret,a[i][s.num[i]] + DFS2(s));
            s.num[i]--;
        }
    }
    return dp1[s] = ret;
}

int DFS2(State s) {
    if (dp2.find(s) != dp2.end()) return dp2[s];
    int ret = 1e9;
    for (int i = 1; i <= n; i++) {
        if (i == n && s.num[n] == m - 1 && s.num[n - 1] == m) return -b[n][m];
        if (s.num[i] < m && (i == 1 || s.num[i] < s.num[i - 1])) {
            s.num[i]++;
            ret = min(ret,-b[i][s.num[i]] + DFS1(s));
            s.num[i]--;
        }
    }
    return dp2[s] = ret;
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d",&a[i][j]);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d",&b[i][j]);
        }
    }
    State begin;
    memset(begin.num,0,sizeof(begin.num));
    printf("%d\n",DFS1(begin));
    return 0;
}
posted @ 2021-07-09 13:48  kjd123456  阅读(38)  评论(0编辑  收藏  举报