P1478 陶陶摘苹果(升级版)

2 篇文章 0 订阅
2 篇文章 0 订阅

题目描述
又是一年秋季时,陶陶家的苹果树结了n个果子。陶陶又跑去摘苹果,这次她有一个a公分的椅子。当他手够不着时,他会站到椅子上再试试。
这次与NOIp2005普及组第一题不同的是:陶陶之前搬凳子,力气只剩下s了。当然,每次摘苹果时都要用一定的力气。陶陶想知道在s<0之前最多能摘到多少个苹果。
现在已知n个苹果到达地上的高度xi,椅子的高度a,陶陶手伸直的最大长度b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气yi,求陶陶最多能摘到多少个苹果。
输入输出格式
输入格式:

第1行:两个数 苹果数n,力气s。
第2行:两个数 椅子的高度a,陶陶手伸直的最大长度b。
第3行~第3+n-1行:每行两个数 苹果高度xi,摘这个苹果需要的力气yi。
输出格式:

只有一个整数,表示陶陶最多能摘到的苹果数。

输入输出样例

输入样例#1:
8 15
20 130
120 3
150 2
110 7
180 1
50 8
200 0
140 3
120 2

输出样例#1:
4

说明
所有数据:n<=5000 a<=50 b<=200 s<=1000
xi<=280 yi<=100

方法一:dfs

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int n, s;//苹果数n,力气s
int a, b;//椅子高a,手伸直高b
int xi[5005], yi[5005];//苹果高度xi,摘下所需力气yi
int f[5005][1005];//记忆化搜索,注意要用二维数组。
//同样是判断第i个苹果时的已取数量f[i],剩余体力s不一样代表的f[i]也不一样,所以不能用一维数组
int dfs(int i,int s)
{
 if (i == n+1 )//如果dfs到了第n+1个苹果,就返回
  return 0;
 if (f[i][s])//用记忆化搜索的优化,如果f中有值就不用再继续搜索了,直接返回f中的值
  return f[i][s];
 int maxn = dfs(i + 1, s);//dfs所有不拿苹果的情况
 if (s >= yi[i] && a + b >= xi[i])//如果满足够得着苹果,体力也够的条件
 {
  maxn = max(dfs(i + 1, s - yi[i]) + 1, maxn);//dfs拿该苹果的情况,和之前算出的不拿该苹果的情况中取大值
  //dfs(i + 1, s - yi[i]) + 1表示取该苹果,取到的苹果数加一
 }
 return f[i][s]=maxn;//给f赋值并返回
}
int main()
{
 memset(f, 0, sizeof(f));
 cin >> n >> s >> a >> b;
 for (int i = 1; i <= n; i++)
 {
  cin >> xi[i] >> yi[i];
 }
 cout << dfs(1,s ) << endl;//从第一个苹果,剩余体力为s时开始搜索
 //system("pause");
 return 0;
}

方法二:dp


#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int n, s;//苹果数n,力气s
int a, b;//椅子高a,手伸直高b
int xi[5005], yi[5005];//苹果高度xi,摘下所需力气yi
int dp[5005][1005];//代表面对第i个苹果,力气为j时已经取过的苹果数
//动态转移方程为dp[i][s]=max(dp[i][s],dp[i-1][s-yi[i]]+1);
int main()
{
 cin >> n >> s >> a >> b;
 memset(dp, 0, sizeof(dp));
 for (int i = 1; i <= n; i++)
 {
  cin >> xi[i] >> yi[i];
 }
 for (int j = 0; j <= s; j++)//枚举力气为0到s每一种情况
  for(int i=1;i<=n;i++)//枚举每一个苹果
  {
   dp[i][j] = dp[i - 1][j];//从前一个状态转移过来
   if (a + b >= xi[i] && j >= yi[i])//满足够得着、力气够的条件
    dp[i][j] = max(dp[i][j], dp[i - 1][j - yi[i]] + 1);//动态转移方程,取苹果和不取苹果的最大值
  }
 cout << dp[n][s] << endl;//输出的是枚举过每一个苹果且力气为s时的最终答案
 //system("pause");
 return 0;
}

方法三:贪心(本题最优)

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int n, s;//苹果数n,力气s
int a, b;//椅子高a,手伸直高b
int cnt;//计算能摘到的苹果数
struct apple
{
 int xi, yi;//苹果高度xi,摘下所需力气yi
}ap[5005];
int cmp(apple a, apple b)//重载sort函数,按照苹果高度升序排序
{
 return a.yi < b.yi;
}
int main()
{
 cnt = 0;
 cin >> n >> s >> a >> b;
 for (int i = 1; i <= n; i++)
 {
  cin >> ap[i].xi >> ap[i].yi;
 }
 sort(ap + 1, ap + n + 1, cmp);//按照苹果的高度从低到高排序
 for (int i = 1; i <= n; i++)//遍历从第一个到第n个苹果
 {
  if (a + b >= ap[i].xi&&s >= ap[i].yi)//满足够得到苹果且力气够用的条件
  {
   cnt++;//结果加一
   s -= ap[i].yi;//更新剩余力气
  }
 }
 cout << cnt << endl;
 //system("pause");
 return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值