L
题意
起始有
m
m
的价值,已知有 轮抉择,每轮抉择有三种,分别为
ai, bi, ci
a
i
,
b
i
,
c
i
其中任何一个值为
0
0
表示当前不可选。否则,可以选择将当前价值 的一种。
若最后的总价值大于等于
k
k
,则为 ,若最后的总结值小于等于
l
l
,则为 ,否则为
NormalEnding
N
o
r
m
a
l
E
n
d
i
n
g
。已知
A
A
先手想要 ,
B
B
想要 ,问最后的结果是什么。
思路
我们无法确定当前轮抉择的原因是,不知道当前选择会对最后结果产生什么样的影响,但我们知道,
A
A
想让结果越大越好, 想让结果越小越好,那么我们就从后往前
dp
d
p
,
dp[i][j]
d
p
[
i
]
[
j
]
维护当在第
i
i
轮,总价值为 时,所能得到的最优结果,因为这个最优是对
AB
A
B
相对而言的,所以根据当前是谁的轮次,维护最大值或者最小值即可。
有如下状态转移方程
又由于本题中 j j 的范围是 ,所以我们需要让 j j 向后偏移,之后注意遍历时的上下界即可
代码
int dp[maxn][205];
int a[maxn], b[maxn], c[maxn];
int bs = 100;
int main()
{
int n, m, k, l;
sdd(n, m);
sdd(k, l);
rep(i, 0, n)
sddd(a[i], b[i], c[i]);
rep(i, 0, 201)
dp[n][i] = i;
per(i, 0, n) {
rep(j, 0, 201) {
if(i & 1) { // B
dp[i][j] = 200;
if(a[i]) dp[i][j] = min(dp[i][j], dp[i+1][min(200, j+a[i])]);
if(b[i]) dp[i][j] = min(dp[i][j], dp[i+1][max(0, j-b[i])]);
if(c[i]) dp[i][j] = min(dp[i][j], dp[i+1][200-j]);
}
else { // A
dp[i][j] = 0;
if(a[i]) dp[i][j] = max(dp[i][j], dp[i+1][min(200, j+a[i])]);
if(b[i]) dp[i][j] = max(dp[i][j], dp[i+1][max(0, j-b[i])]);
if(c[i]) dp[i][j] = max(dp[i][j], dp[i+1][200-j]);
}
}
}
if(dp[0][bs+m] >= bs+k) puts("Good Ending");
else if(dp[0][bs+m] <= bs+l) puts("Bad Ending");
else puts("Normal Ending");
return 0;
}
小结
倒着 dp d p 可以是的当前轮次的选择有据可依,也就满足了“博弈时双方均会选择最优解”的这一点。妙啊
思路
另给出一个记忆化搜索过的代码,正确性证明类似于递归的出口是 i==n i == n 所以类似于倒着 dp d p ,两者一个是类似于 bfs b f s ,一个类似于 dfs d f s ,但是第一种只用了 2ms 2 m s ,第二种用了 25ms 25 m s 可能没差吧 = =
代码
int dp[maxn][205];
int a[maxn], b[maxn], c[maxn];
int bs = 100;
int n, m, l, k;
int dfs(int i, int j){
if(i == n){
if(j >= k+bs) return 2;
if(j > l+bs) return 1;
return 0;
}
if(dp[i][j] != -1) return dp[i][j];
if(i&1) { // B
int minn = 2;
if(a[i]) minn = min(minn, dfs(i+1, min(j+a[i], 200)));
if(b[i]) minn = min(minn, dfs(i+1, max(j-b[i], 0)));
if(c[i]) minn = min(minn, dfs(i+1, 200-j));
return dp[i][j] = minn;
}
else {
int maxx = 0;
if(a[i]) maxx = max(maxx, dfs(i+1, min(j+a[i], 200)));
if(b[i]) maxx = max(maxx, dfs(i+1, max(j-b[i], 0)));
if(c[i]) maxx = max(maxx, dfs(i+1, 200-j));
return dp[i][j] = maxx;
}
}
int main()
{
mm(dp, -1);
sdd(n, m);
sdd(k, l);
rep(i, 0, n)
sddd(a[i], b[i], c[i]);
rep(i, 0, 201)
dp[n][i] = i;
int judge = dfs(0, m+bs);
if(judge == 2) puts("Good Ending");
else if(judge == 0) puts("Bad Ending");
else puts("Normal Ending");
return 0;
}
Orz O r z