题目大意:
有n头牛赛跑,每头牛初始体力值为e,至少要一头牛跑d圈,每分钟可以跑任意圈数x,但是需要一头牛来领跑,领跑的牛需要消耗x^2的体力值,其他牛只需要消耗x的体力值,问最少需要多少分钟
分析:
DP
一开始没想到最优方案一定是1~n每头牛都依次进行领跑,所以就没想出来DP方程O(≧口≦)O
f[i][j][k]代表i-1头牛已经进行了领跑,i牛即将进行领跑,已经跑了j圈,i牛已经消耗了k体力值
为什么要这么想呢?因为我们如果要转移到我们的目标状态——跑了d圈所需时间,那么我们就要知道每分钟跑了几圈,而每分钟跑几圈的决定权在于当前领跑的牛,如果要所需时间最短,我们当然希望每分钟跑的圈数越多越好,但是不行,什么是限制呢?—–牛的剩余体力,所以我们的状态转移所需要的信息为:当前已经跑了几圈,那头牛即将领跑以及它的剩余体力值
接下来就是怎么转移的问题了:根据我们的已知信息和目标状态,我们可以知道,我们需要变化的是j也就是圈数,而体力值以及那头牛领跑都是为圈数服务滴,所以我们枚举s,当前领跑的牛要跑s圈进行转移:f[i][j+s][j+s*s]=min(f[i][j][k]+1)(为什么不是转移到i+1牛捏??因为我们不知道i+1牛的已消耗体力值没办法转移呀)
,那么i+1牛需要用啥来转移捏??那就是f[i+1][j][j]=min(f[i][j][k])i牛一圈也不领跑,直接神圣的任务转让给i+1牛,因为我们的i代表的是i-1头牛进行了领跑,而我们规定这些牛是依次领跑,所以说明i+1牛未进行领跑,它的消耗体力值就是跑的圈数j,是不是很有道理 O(∩_∩)O哈哈~
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;
int n,d,e,f[20+5][100+5][100+5];
signed main(void){
scanf("%d%d%d",&n,&e,&d);
for(int i=0;i<=n;i++)
for(int j=0;j<=d;j++)
for(int k=0;k<=e;k++)
f[i][j][k]=inf;//memset TLE 循环 AC
f[1][0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=d;j++)
for(int k=0;k<=e;k++)
if(f[i][j][k]!=inf){
for(int s=0;j+s<=d&&k+s*s<=e;s++)
f[i][j+s][k+s*s]=min(f[i][j][k]+1,f[i][j+s][k+s*s]);
if(i!=n)
f[i+1][j][j]=min(f[i][j][k],f[i+1][j][j]);
}
int ans=inf;
for(int i=0;i<=e;i++)
ans=min(ans,f[n][d][i]);
cout<<(ans==inf?0:ans)<<endl;
return 0;
}
by >o< neighthorn