Cpp环境【CQYZOJ1836】【Code[VS]5230】猴子
2016-08-07 16:20
183 查看
【问题描述】
一只猴子找到了很多香蕉树,这些香蕉树都种在同一直线上,而猴子则在这排香蕉树的第一棵树上。这只猴子当然想吃尽量多的香蕉,但它又不想在地上走,只想从一棵树跳到另一棵树上.同时猴子的体力有限,它不能一次跳得太远或跳得次数太多,每当他跳到一棵树上,就会把那棵树上的香蕉都吃掉。那么,它最多能吃多少个香蕉呢?
【输入格式】
输入第一行为三个整数,分别是香蕉树的棵数N,猴子每次跳跃的最大距离D,最多跳跃次数M.
下面N行每行包括两个整数,ai,bi分别表示每棵香蕉树上的香蕉数,以及这棵树到猴子所在树的距离。输入保证这些树按照从近到远排列,并且没有两棵树在同一位置。b0总是为0 .
【输出格式】
输出只有一行,包含一个整数,为猴子最多能吃到的香蕉数。
【输入样例】
5 5 2
6 0
8 3
4 5
6 7
9 10
【输出样例】
20
【数据范围】
ai<=10000,d<=10000
对于30%的数据,有M<=N<=10,bi<=100
对于50%的数据,有M<=N<=30,bi<=1000
对于100%的数据,有M<=N<=100,bi<=10000
【来源】
三校联考试题
Code[VS]5230 原题传送矩阵
重庆一中题库 原题传送矩阵
【思路梳理】
DP水题,非常简单,也比较适合给刚刚入门的OIer练手,熟悉一下考场上比较简单的动态规划题目。
首先考虑直接粗暴的回溯算法,预期得分30分,因为要跳至多m次(至少则是0次),每次可能的方案数至多为n,所以时间复杂度不稳定,最坏为
(并没有那么大):
void solve(int jump_time,int tot,int id) {//jump_time为当前已经跳过了的次数,tot为总收益,id为当前所处的位置 if(jump_time>m || id>=n)//体力耗尽或者走到终点两种情况都是回溯出口 { ans=max(ans,tot);//择优 return; } for(int i=id+1;i<=n;i++)if(dist[i]-dist[id]<=d)//寻找在编号为id的树的后面的树i使得猴子能够从id跳到i。 solve(jump_time+1,tot+weight[i],i); ans=max(ans,tot);//需要注意的是,猴子可能在第id棵树已经无法跳到第id+1棵树。 }
考虑动态规划:
当前状态怎么转移过来?从最优的上一次跳跃的终点转移过来。
最优的上一次跳跃的终点怎么找?找能够跳到当前树的所有树中权值和最优的。
当前状态怎么变化?收益要加上这一棵树上的所有果实数。
由此可以写出:
状态函数:f(i,j)=猴子经过i次跳跃到达第j棵树时最多能够吃到的香蕉数
状态转移方程:f(i,j)={max(f(i-1,k)+weight[j] | i-1<=k && dist[j]-dist[k]<=D}
时间复杂度远小于
(因为随着第一重循环次数增加,第二重循环的j循环的范围在缩小,k始终在i-1~j这个区间内)。
【Cpp代码】
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define maxn 105 using namespace std; int n,D,m,weight[maxn],dist[maxn],ans=0; int d[maxn][maxn]; void dp() { //f(i,j)=猴子经过i次跳跃到达第j棵树时最多能够吃到的香蕉数 memset(d,-1,sizeof(d)); //f(i,j)={max(f(i-1,k)+weight[j] | i-1<=k && dist[j]-dist[k]<=D} d[0][1]=ans=weight[1];//边界:跳跃0次,猴子处于第一棵树 for(int i=1;i<=m;i++) for(int j=i;j<=n;j++)if(dist[j]<=i*D && dist[j]>=i) {//每一次必须要往前面跳,意味着如果猴子能跳到下棵树就至少要往前跳1棵树;总共跳了i次,起点是1,那么至少要在i+1棵树的位置; //同样基于上面的原理,那么最少dist[j]要大于等于i(每一次往前跳1),且小于等于i*D(每一次都往前跳到最远) int t=-1; for(int k=j-1;k>=i;k--)if(dist[j]-dist[k]<=D && d[i-1][k]!=-1) {//d[i-1][k]!=-1,如果第i-1次跳跃不能够到达k那么也不可能在第i次从k跳到j t=max(t,d[i-1][k]); } if(t!=-1) d[i][j]=t+weight[j];//猴子能从至少一棵树在第i次跳跃中跳到j ans=max(ans,d[i][j]);//随时都有可能无法再往前跳了,所以每一次填表都应该记录 } cout<<ans; } int main() { scanf("%d%d%d",&n,&D,&m); for(int i=1;i<=n;i++) scanf("%d%d",&weight[i],&dist[i]); dp(); return 0; }
相关文章推荐
- Cpp环境【Code[VS]5226】物品选取
- Cpp环境【TYVJ1153】【Code[VS]4093】【CQYZOJ16874】 间谍网络
- Cpp环境【Code[VS]5227】【JSOI2010】盛夏的果实
- Cpp环境【NOIP2006提高组】【Code[VS]1155】【Vijos1399】 金(精)明的预算
- Cpp环境【Code[VS]4175】【CQYZOJ1824】收费站
- Cpp环境【SDUT1128】【Code[VS]1809】【CQYZOJ1823】河床
- Codevs5230【三校联考试题】 猴子(重庆一中高2018级信息学竞赛测验8) 解题报告
- Cpp环境【Code[VS]1084】【NOIP2003普及组】乒乓球
- Cpp环境【CQYZOJ1496】【Code[VS]5287】搬家大冒险
- vscode cpp cmake 环境搭建
- Cpp环境【NOIP2010提高组】【Vijos1777】【Code[VS]1066】【CQYZOJ1793】引水入城
- Cpp环境【NOIP2003 P3】【Vijos1100】【Code[VS]1090】【CQYZOS2816】加分二叉树
- Cpp环境【Tyvj1011】【Code[VS]1169】传纸条
- Cpp环境【NOIP2015 D1P2】【Viijos1979】【Code[VS] 4511】【CQYZOS3198】 信息传递
- VS Code1.4 搭建Golang的开发调试环境(遇到很多问题)
- .NET Core VS Code 环境配置
- Windows环境下vscode-go安装笔记
- [置顶] win10下配置VS Code C/C++编译环境(TDM-GCC)
- VSCode python环境运行搭建