CF917B MADMAX
题意:
Alice和Bob有一个n个点m条边的DAG,每条边上有一个小写英文字母表示权值,Alice和Bob每人有一个棋子,每个人放在一个节点上(可以放在同一个节点上)。 第一轮Alice可以沿一条边把棋子移到一个相邻的节点上,之后Bob沿一条边移动棋子,以此类推,规则规定:每一次移动经过的边的ASCII码单调不降(即,若Alice沿’c’走了一步,Bob只能沿’c’或’c’之后的字母走,然后Alice又要沿Bob走过的字母之后的字母走…)。不能走的人输掉这盘游戏。 现在他们想知道,给定初始位置,两人都按最优策略,谁会赢?
题解:
枚举起点,正常模拟博弈过程
sg[x][y][kw]:先手为x,后手为y,字母限制不超过kw的这个状态的sg值
如果sg==0说明先手输,sg=1说明先手赢
v是u的下一个状态
如果全部sg[v]是1,sg[u]为0
如果存在sg[v]是0,sg[u]为1
上面这两个条件怎么实现呢?
我们令sg[u]为0,然后去找v,如果有一个v使得sg[v]是0,说明sg[v]=1
当不能走时即输掉比赛,此时sg为0
dfs模拟过程,记忆化搜索+dp实现
复杂度O(26 * N^2 + 26 * N * M)
26 * N * N是枚举起点
26 * N * M是dfs
代码:
#include<bits/stdc++.h>
#define INF (1<<25)
#define MAXN 105
#define LL long long
using namespace std;int N,M;struct edge{int v,w;edge(int v=0, int w=0):v(v), w(w){}
};vector<edge> adj[MAXN];int sg[MAXN][MAXN][26];
//sg = 0/1 lose/win
//sg[u] = 0, if all sg[v] = 1
//sg[u] = 1, if some sg[v] = 0 bool dfs(int x, int y, int kw){if(sg[x][y][kw] != -1) return sg[x][y][kw];sg[x][y][kw] = 0;int v,w;for(int k=0;k<adj[x].size();k++){v = adj[x][k].v;w = adj[x][k].w;if(w < kw) continue;//必须满足字母非上升序列 if(dfs(y,v,w)==0){sg[x][y][kw] = 1;break;}}return sg[x][y][kw];
}int main(){cin>>N>>M;int u,v;char c;for(int i=1;i<=M;i++){cin>>u>>v>>c;adj[u].push_back(edge(v,c-'a'));}memset(sg,-1,sizeof(sg));//初始化为-1 for(int i=1;i<=N;i++){for(int j=1;j<=N;j++){if(dfs(i,j,0)) cout<<"A";else cout<<"B";}cout<<endl;}return 0;
}