Codeforces 917B MADMAX (DP+博弈)

<题目链接>

题目大意:
给定一个DAG图,其中图的边权是给定的字符所对应的ascii码,现在A先手,B后手,每次沿DAG图走一步,但是第i次走的边权一定要大于等于第i-1次走的边权(这里是值两个人一起的第$i$次,不是一个人走动的第$i$次),最先无法走动的人输。让你对$A,B$的起始位置邻接矩阵$(i,j)$(代表A从$i$点出发,$B$从$j$点开始出发),对应给出他们的胜负情况,如果A胜,输出A,反之,输出B。

解题分析:

$dp[x][y][k]$表示先手$x$,后手$y$,边权为$k$对应的胜负情况。

对于$x$所有能够直接到达的点$v$,状态转移为$dp[y][v][nowval]$,前一个状态的后手$y$变成了当前的先手状态,$nowval$表示$x->v$的边权。

如果存在至少一个$v$,使得$dp[y][v][nowval]$为必败状态,则上一个状态$dp[x][y][k]$为必胜状态(因为他们都是选择最优的情况走)。

$dp[x][y][k]=0$表示先手必败,反之则必胜。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define fi first
#define se second
#define pb push_back
const int N = 110;

int dp[N][N][130];
typedef pair<int,int>P;
vector<P>G[N];
int n,m;

bool DP(int x,int y,int k){
    if(dp[x][y][k]!=-1)return dp[x][y][k];
    for(int i=0;i<G[x].size();i++){
        int v=G[x][i].fi,cost=G[x][i].se;
        if(cost>=k && DP(y,v,cost)==0)    //如果下一步存在先手必败的情况,则这一步先手必胜
            return dp[x][y][k]=1;
    }
    return dp[x][y][k]=0;     //为0表示先手必败
}
int main(){
    cin>>n>>m;
    rep(i,1,m) {
        int u,v;char c;cin>>u>>v>>c;
        G[u].pb(P(v,c));
    }
    memset(dp,-1,sizeof dp);
    rep(i,1,n) rep(j,1,n){
        DP(i,j,0);
    }           
    rep(i,1,n) { 
        rep(j,1,n)
            printf("%c",dp[i][j][0]?'A':'B');
        puts("");
    }
}
原文地址:https://www.cnblogs.com/00isok/p/10799454.html