題目描述
又是一年秋季時,陶陶家的蘋果樹結了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;
}