题源 贪心,递归,记忆化,剪枝,动态规划
题目描述
又是一年秋季时,陶陶家的苹果树结了 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;
}
呼~~~ 到此结束,睡觉