Codeforces 918D MADMAX 图上dp 组合游戏

题目链接

题意

给定一个 \(DAG\),每个边的权值为一个字母。两人初始各占据一个顶点(可以重合),轮流移动(沿着一条边从一个顶点移动到另一个顶点),要求每次边上的权值 \(\geq\) 上一次的权值。无法移动者输。

要求:对所有可能的初始情况,给出一张胜负表。

思路

特殊情况

  1. 两人在同一个顶点上,那么必然是先手输;
  2. 如果有\(u\rightarrow v\)边,并且先手在 \(u\) 上,后手在 \(v\) 上,且先手此时可以移动(判断边的权值),那么必然是先手赢

一般情况

考虑用 \(dp[u][v][w]\) 表示先手在 \(u\),后手在 \(v\),上一次移动的权值为 \(w\) 时,先手能否移动。

如果有 \(u\rightarrow x\) 可行(权值\(ww\geq w\)) 且 \(dp[v][x][ww]==false\),那么意味着先手只要走到 \(x\),后手就无路可走了。因此,先手有必胜策略;否则先手必败。

因为是 \(DAG\),所以可以用记忆化搜索。

联想

其实这里如果联想到 组合游戏 就很好理解了。

如果一个状态的所有后继都是先手必胜态(N),那么这个状态是先手必败态(P)。

如果一个状态能走到某一个先手必败态(P),那么这个状态就是先手必胜态(N)。

如果不考虑搜索复杂度的话,组合游戏其实也就是:在给定的DAG上确定状态是P态还是N态。而这道题恰好点数比较少,故真的就可以直接搜索了。

Code

#include <bits/stdc++.h>
#define maxn 110
#define maxm 5010
using namespace std;
typedef long long LL;
int mp[maxn][maxn];
int ne[maxn], tot;
struct Edge { int to, ne, w; }edge[maxm << 1];
bool vis[maxn][maxn][26], dp[maxn][maxn][26];
void add(int u, int v, int c) {
    edge[tot] = {v, ne[u], c};
    ne[u] = tot++;
}
int dfs(int u, int v, int ch) {
    if (vis[u][v][ch]) return dp[u][v][ch];
    vis[u][v][ch] = true;
    if (u == v) return false;
    if (mp[u][v]) {
        if (ch <= mp[u][v]) return dp[u][v][ch] = true;
    }
    for (int i = ne[u]; ~i; i = edge[i].ne) {
        int x = edge[i].to; char ww = edge[i].w;
        if (ch <= ww && !dfs(v, x, ww)) return dp[u][v][ch] = true;
    }
    return false;
}
int main() {
    memset(ne, -1, sizeof ne);
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; ++i) {
        int u, v; char c;
        scanf("%d%d %c", &u, &v, &c);
        mp[u][v] = c-'a';
        add(u, v, c-'a');
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            putchar(dfs(i, j, 0) ? 'A' : 'B');
        }
        puts("");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/8386936.html

时间: 2024-10-10 16:23:26

Codeforces 918D MADMAX 图上dp 组合游戏的相关文章

ZOJ 3644 Kitty&#39;s Game (图上DP 约数)

哎-这一场就做了三个题目,全队倒数第一,简直是太弱了. A Kitty's Game (ZOJ 3644) 题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3644 题意: 给出一个有向图,每个节点有一个权值pi, 有一个人从1节点出发(其权值为1节点的权值),前往n号节点,每经过一个节点,他的权值就变成了他经过这个节点前的权值和这个节点权值的最小公倍数,如果他经过这个节点后权值不发生变化则他就不能经过这个节点

poj 3635 Full Tank? ( 图上dp )

题意: 已知每个点的加油站的油价单价(即点权),每条路的长度(边权). 有q个询问,每个询问包括起点s.终点e和油箱容量. 问从起点走到终点的最小花费.如果不可达输出impossible,否则输出最小的旅途费用. 算法: 其实要分析状态= =感觉就像是dp. 最直接的想法是  每到一个点都加上要走到下一个点所需要的油量.但是走的路不同,到底怎么处理加多少的问题呢? 因此想到分解状态,即拆点.每到一个点都+1单位的油量,然后把这个状态加入队列.另外如果现在油箱内的油足够达到下一点, 则更新状态,把

zoj1232Adventure of Super Mario(图上dp)

题目连接: 啊哈哈,点我点我 思路: 这个题目是一个图上dp问题,先floyd预处理出图上所有点的最短路,但是在floyd的时候,把能够用神器的地方预处理出来,也就是转折点地方不能为城堡..预处理完毕后,就是一个dp问题了...dp[][],两维分别表示到达的地点和使用神器的次数..这样这个问题就得到了解决.. 题目: Adventure of Super Mario Time Limit: 2 Seconds      Memory Limit: 65536 KB After rescuing

Codeforces 918D - MADMAX

918D - MADMAX 思路: dp+记忆化搜索 状态:dp[i][j][w]表示先手在i节点,后手在j节点,这一轮的字母为w的结果,如果为true,则表示先手必赢,否则后手必赢. 状态转移:如果i连的一条边的权值tw>=w,连向t,那么这个博弈的结果可以由dp[j][t][tw]决定,如果dp[j[t][tw]为false,那么dp[i][j][w]肯定为true(因为先手可以选择走这条边使对于对方来说后手必赢),如果不为false,可以选择不走这条路,如果所有边走过去都不能使dp[i][

【POJ3710】Christmas Game 博弈 有限制的图上删边游戏(树形删边游戏进化1)

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42671885 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题意: 一个树图,然后1永远是根,两人轮流删边,不能删者输. 删边限制:只能删跟1连通的边. 树图限制: 它首先是一棵树,然后某些点上可能带一个环 原描述:最开始的图是一颗带有一些简单环的树,然后任何边都至多在一个多边形上.每个多边形最多有一个节点出现在主树上. 给个神犇论文地址: 石家庄二中·贾志豪-- <组合

poj 3249 Test for Job 图上dp(记忆化搜索)

题意: 给一个n个点的DAG,每个点有一个值p,现在要在图上找一个入度为0到出度为0的路径,使路径上的点的p值和最大. 分析: dp[v]记录以点v为起点能获得的最大值,搜一遍即可. 代码: //poj 3249 //sep9 #include <iostream> using namespace std; const int maxN=100024; const int maxM=1000024; int n,m,e; int p[maxN],head[maxN],dp[maxN],vis[

Codeforces Round #455 (Div. 2) E. Coprocessor DAG图上dp

E. Coprocessor 题意:n 个任务,每个任务在 主 / 副 处理器上执行.每个任务可能依赖于其它的一些任务,副处理器每次可以处理多个任务.但如果一个任务要在副处理器上执行,那它所依赖的任务要么已执行完了,要么和它一起在这个副处理器上同时执行.问副处理器最少调用多少次. 直白一点讲,就是给出一个 DAG 图,n 个点, m 条边,每个点的权值为 0 或1 .操作:直接相互连通的权值为 1 的点可以一次处理掉. 问最少操作多少次. tags:因为是DAG 图,直接跑 dp dp[i] 表

HDU 3249 Test for job (有向无环图上的最长路,DP)

 解题思路: 求有向无环图上的最长路,简单的动态规划 #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <cmath> #define LL long long using namespace std; const int

hdu 5001 概率DP 图上的DP

http://acm.hdu.edu.cn/showproblem.php?pid=5001 当时一看是图上的就跪了 不敢写,也没退出来DP方程 感觉区域赛的题  一则有一个点难以想到 二则就是编码有点难度. 这个题: 我一直的思路就是1-能到达i的概率 就是不能到达i的概率,然后三维方程巴拉巴拉,,,,把自己搞迷糊 正确做法: dp[k][j]   经过j步到达k点 并且不经过i点的概率 这么设的原因是,就可以求不能到达i点的概率了.   不能到达i点的概率就是segma(dp[v][j-1]