题目描述
又是一年秋季时,陶陶家的苹果树结了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;
}