POJ 1946 Cow Cycling


题目大意:
有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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值