2020-11-16
dp
918D 1700
题目
原题链接:https://codeforces.com/problemset/problem/918/D
思路
题目大意:给定一个 DAG,每个边的权值为一个字母。两人初始各占据一个顶点(可以重合),轮流移动(沿着一条边从一个顶点移动到另一个顶点),要求每次边上的权值 ≥上一次的权值。无法移动者输。要求:对所有可能的初始情况,给出一张胜负表。
思路:
图上DP我真的一脸懵逼,2000+的题都没这恐怖,图涂
思路来自 https://www.cnblogs.com/kkkkahlua/p/8386936.html
思路我就不写了 涂
大佬强的
代码实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <queue>
using namespace std;
#define mes0(c) memset((c),0,sizeof(c))
#define mesi(c) memset((c),ifi,sizeof(c))
#define mes(c,n) memset((c),(n),sizeof(c))
#define fsios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define rep1(n) for (int i=1;i<=(n);i++)
#define rep2(n) for (int j=1;j<=(n);j++)
#define inp(a, n) for (int i = 1; i <= (n); i++) cin >> a[i];
#define ll long long
#define fi first
#define se second
const ll MAX = 200;
const int ifi = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
int mp[MAX][MAX];
int dp[MAX][MAX][30];
int vis[MAX][MAX][30];
bool dfs(int u, int v, int w) {
if (vis[u][v][w]) return dp[u][v][w];//记忆化
if (u == v) return dp[u][v][w] = false;//同起点先手必输
if (mp[u][v] && w <= mp[u][v]) return dp[u][v][w] = true;//uv有路且可行则先手必赢
vis[u][v][w] = 1;
for (int i = 1; i <= n; i++) {
if (mp[u][i] && w <= mp[u][i] && !dfs(v, i, mp[u][i]))
return dp[u][v][w] = true;
}
return dp[u][v][w] = false;
}
int main() {
fsios;
while (cin >> n >> m) {
int u, v; char c;
mes0(mp); mes0(dp); mes0(vis);
rep1(m) {
cin >> u >> v >> c;
mp[u][v] = c - 'a' + 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << (dfs(i, j, mp[i][j]) == false ? 'B' : 'A');
}
cout << endl;
}
}
return 0;
}