陶陶摘苹果(升级版)

文章对比了贪心、递归、记忆化搜索和剪枝策略在解决陶陶摘苹果问题中的应用,最终推荐使用动态规划求解,类比0/1背包问题
摘要由CSDN通过智能技术生成

题源 贪心,递归,记忆化,剪枝,动态规划

题目描述

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

说明/提示

对于 100% 的数据,n≤5000, a≤50, b≤200, 0s≤1000, 0xi​≤280, yi​≤100。

贪心正解: 

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
 
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
 int main()
 {
 	int n,s;
 	int a,b;
 	int h=0,ant=0;
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);//按照力气排序
	for(int i=1;i<=n;i++){
		if(q[i].yi<=s&&h>=q[i].xi){
			ant++;
			s-=q[i].yi;
		}
	}
	cout<<ant;
 	return 0;
  } 

 递归,肯定不是正解

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
int n,s;
int a,b;
int h=0,ant=0;
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
int maxn=-1;
void dfs(int t,int s,int sum){
	if(t==n+1||s==0){
		maxn=max(maxn,sum);
		return ;
	}
	
	for(int i=t;i<=n;i++){
	    if(q[i].yi<=s&&h>=q[i].xi){
		    dfs(i+1,s-q[i].yi,sum+1);
       }
	}
//	maxn=max(maxn,sum);
}
 int main()
 {
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);
	for(int i=1;i<=n;i++){//只是为了观察排序后的情况,没啥作用
		cout<<q[i].xi<<" "<<q[i].yi;
		cout<<endl;
	}
	dfs(1,s,0);
	cout<<maxn;
 	return 0;
  } 

递归第二种写法

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
int n,s;
int a,b;
int h=0,ant=0;
int dp[5050][5050]={0};
int sg[5050][5050]={0};
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
int maxn=-1;
int dfs(int t,int s){
	if(t==n+1||s==0){
		return 0;
	}
	int maxn=dfs(t+1,s);
	if(q[t].yi<=s&&h>=q[t].xi){
		maxn=max(maxn,dfs(t+1,s-q[t].yi)+1);
	}
	return maxn;
}
 int main()
 {
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);
	for(int i=1;i<=n;i++){
		cout<<q[i].xi<<" "<<q[i].yi;
		cout<<endl;
	}
	maxn=dfs(1,s);
	cout<<maxn;
 	return 0;
  } 

记忆化搜索?像吗?管他的,不是太清楚

这一做法欠佳

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
int n,s;
int a,b;
int h=0,ant=0;
int dp[5050][5050]={0};
int sg[5050][5050]={0};
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
int maxn=-1;
int dfs(int t,int s){
	if(t==n+1||s==0){
		return 0;
	}
	if(dp[t][s]) return dp[t][s];
	dp[t][s]=dfs(t+1,s);
	if(q[t].yi<=s&&h>=q[t].xi){
		dp[t][s]=max(dp[t][s],dfs(t+1,s-q[t].yi)+1);
	}
	return dp[t][s];
//	int maxn=dfs(t+1,s);
//	if(q[t].yi<=s&&h>=q[t].xi){
//		maxn=max(maxn,dfs(t+1,s-q[t].yi)+1);
//	}
//	return dp[t][s]=maxn;
}
 int main()
 {
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);
	for(int i=1;i<=n;i++){
		cout<<q[i].xi<<" "<<q[i].yi;
		cout<<endl;
	}
	cout<<dfs(1,s);
 	return 0;
  }  

剪枝+记忆化吗,这种做法是欧克嘞

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
int n,s;
int a,b;
int h=0,ant=0;
int dp[5050][5050]={0};
int sg[5050][5050]={0};
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
int maxn=-1;
int dfs(int t,int s){
	if(t==n+1||q[t].yi>s||s==0){//加了 q[t].yi>s将没必要的搜索丢弃掉 
		return 0;
	}
	if(dp[t][s]) return dp[t][s];
	dp[t][s]=dfs(t+1,s);
	if(q[t].yi<=s&&h>=q[t].xi){
		dp[t][s]=max(dp[t][s],dfs(t+1,s-q[t].yi)+1);
	}
	return dp[t][s];
//	int maxn=dfs(t+1,s);
//	if(q[t].yi<=s&&h>=q[t].xi){
//		maxn=max(maxn,dfs(t+1,s-q[t].yi)+1);
//	}
//	return dp[t][s]=maxn;
}
 int main()
 {
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);
	for(int i=1;i<=n;i++){
		cout<<q[i].xi<<" "<<q[i].yi;
		cout<<endl;
	}
	cout<<dfs(1,s);
 	return 0;
  }  

动态规划,这种做法最好理解也是完全欧克的,01背包,再多一个条件即可

#include<bits/stdc++.h>
 using namespace std;
 struct app{
 	int xi,yi;
 }q[5050];
int n,s;
int a,b;
int h=0,ant=0;
int dp[5050][5050]={0};
 bool cmp(app q1,app q2){
 	return q1.yi<q2.yi; 
 }
 int main()
 {
 	cin>>n>>s>>a>>b;
 	h=a+b;
	for(int i=1;i<=n;i++){
		cin>>q[i].xi>>q[i].yi;
	}
	sort(q+1,q+1+n,cmp);
	for(int i=1;i<=n;i++){
		for(int j=0;j<=s;j++){
			if(q[i].yi<=j&&h>=q[i].xi){//多了个条件 
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-q[i].yi]+1);//01背包 
			}
			else{
				dp[i][j]=dp[i-1][j];
			}
		}
	} 
	for(int i=1;i<=n;i++){//只是为了观察dp情况,没啥作用 
		for(int j=0;j<=s;j++){
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	} 
	cout<<dp[n][s];
 	return 0;
  }  

 呼~~~ 到此结束,睡觉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值