P1478 陶陶摘蘋果(升級版)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章