DP
啦啦啦,终于开始我最爱的dp啦~~开心~~
虽然它很难想QAQQ
就是喜欢喜欢喜欢喜欢~~
言归正传(好像也没有严肃过)
题目链接:https://www.luogu.org/problem/show?pid=1353
题目大意(dp开始后要写题目大意了QAQ):
有n分钟,每分钟可以选择跑步或休息,
如果跑步,每分钟都有一个最多能跑的距离且疲劳值加一,
如果休息,必须要休息到疲劳值为0才结束休息,
(如果疲劳值为0继续休息不减疲劳值)
开始时疲劳值为0,整个过程不能超过疲劳值m,且在跑完时疲劳值必须为0。
求n分钟内可以跑的最大距离
/*B:这个题是搜索?
A:不不不,这是dp……*/
A:这一分钟的状态可以由前一分钟转移过来呢
A:他这一分钟可以跑可以休息,f[i][i] = max(f[i - 1][j - 1] + d[i],dp[i - 1][j + 1])??
B:不不不,j + 1 ? j - 1?那你要怎么写j的for啊?
A:那我倒着写j + 1的(从m --> 1)??
A:这样??
for(int i = 1;i <= n;++ i){ for(int j = m;j >= 1;-- j){ f[i][j] = max(f[i][j],f[i - 1][j + 1]); } }
B:咦不对啊,dp[i - 1][j + 1]?这样是只休息了一分钟啊?题目要求如果休息那么就要休息到疲劳值为0啊?
A:对对对,所以我不能将单独的一分钟休息看为一个状态去更新其他的状态喽?
B:也就是说……我如果选择休息,我只有把f[i][0]看做一种状态!!
A:嗯嗯,那么 f[i][0] = max(f[i][j],f[i - j][j]) 么?
B:应该就是这样啦~
END.
对于每一分钟都有跑和不跑两种选择(哇哦发现分析dp这是必写句啊23333)
设计状态:f[i][j] 到第i分钟疲劳值为j时能跑的最大距离
设第 i 分钟的疲劳值为 j ,最多能跑的距离为 d[ i ]
1.如果这一分钟选择跑
那前一分钟的疲劳值为 j - 1
这一分钟的最大距离 = 前一分钟的最大距离 + d[i]
方程就出来啦:
f[i][j] = max(f[i - 1][j - 1] + d[i],f[i][j])
2.如果这一分钟休息到疲劳值为0
那往前j分钟的疲劳值为j
方程就是这样子的:
f[i][0] = max(f[i - j][j],f[i][0])
等等等等等等,
你是不是要问为什么不设计这一分钟开始休息?
某大神说这一分钟开始休息是给状态的方程,
设计这一分钟休息到疲劳值为0是要状态的方程。
so,如果可以想到给状态的方程当然可以写~~
但重点是我不会写啊啊啊啊QAQQ
下一个下一个下一个~~~
我们讨论了如果休息到第i分钟刚好疲劳值为0的情况,
那如果我是疲劳值已经为0了,还继续休息呢?
(有没有发现题目就有提醒~~)
很明显这可能也会是最优答案,比如样例
(截自洛谷2333)
所以很显然还有一种情况嘛
3.前一分钟疲劳值已经为0,
这一分钟我仍然休息
我是方程看这里:
f[i][0] = max(f[i][0],f[i - 1][0])
嗯,这个题就这样了
注意第二种情况需要满足 i >= j (想想为什么)
最后输出的就是f[n][0]喽~
Codes:
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5
6 using namespace std;
7 const int N = 10000 + 5;
8 int d[N],m,n,ans;
9 int f[N][500 + 5];//f[i][j]:到第i分钟,疲劳值为j时的最大距离
10 int maxx(int x,int y){if(x > y) return x;return y;}
11 int main(){
12 scanf("%d%d",&n,&m);
13 for(int i = 1;i <= n;++ i){
14 scanf("%d",&d[i]);
15 }
16 for(int i = 1;i <= n; ++ i){
17 for(int j = 1;j <= m;++ j){
18 f[i][j] = maxx(f[i - 1][j - 1] + d[i],f[i][j]);//跑
19 if(i - j >= 0) //休息
20 f[i][0] = max(f[i][0],f[i - j][j]);
21 f[i][0] = max(f[i][0],f[i - 1][0]);//已经到达疲劳为0仍然休息
22 }
23
24 }
25 cout << f[n][0] << '
';
26 return 0;
27 }
MAS(make a summary):
在每一分钟对每种可能的情况分类讨论?
要设计一个可以递推的方程?(设计好状态?)
要想好由什么推到什么?(最好是明显又正确的)
我写的方程是由已知最优推向最优的么?
最后说一句,
我的码风最帅气~~