文章目录:
故事的开头总是极尽温柔,故事会一直温柔……💜
✨你好啊,我是“ 怪& ”,是一名在校大学生哦。
🌍主页链接:怪&的个人博客主页
☀️博文主更方向为:课程学习知识、作业题解、期末备考。随着专业的深入会越来越广哦…一起期待。
❤️一个“不想让我曾没有做好的也成为你的遗憾”的博主。
💪很高兴与你相遇,一起加油!
一、🌳代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int n;
const int N =40;
long long a[N];
int b[N];//记录第i本书是否被放入
long long m;
long long out=99999999999;
void bt(int i,int sum1){
long long x=sum1+a[i]; //将a[i]放入
if(x>=m){//超出m,后续不需再算入
if(x<out) out=x;//更新out
int t_flag=0;
for(int i=1;i<=n;i++){//找到已放入的最大数的坐标t_flag
if(b[i]==1) t_flag=i;
}
if(t_flag!=0){
sum1=sum1-a[t_flag];
b[t_flag]=0;
bt(t_flag+1,sum1);//不放a[t_flag],继续进行
}
}
else{//未超出m
sum1=x;//将a[i]算入
// cout<<"sum1 "<<sum1<<endl;
b[i]=1;
int sum_sy=0;
for(int j=i+1;j<=n;j++) sum_sy+=a[j];
if(i!=n && sum_sy+sum1>=m) bt(i+1,sum1); //i未至n,并且剩余和+sum1可满足题意再继续
else{//i走到n还不够
sum1=sum1-a[i];//不放a[i]
b[i]=0;
int t_flag=0;
for(int i=1;i<=n;i++){//找到已放入的最大数的坐标t_flag
if(b[i]==1) t_flag=i;
}
if(t_flag!=0){
sum1=sum1-a[t_flag];
b[t_flag]=0;
bt(t_flag+1,sum1);//不放a[t_flag],继续进行
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);//排序
bt(1,0);
cout<<out<<endl;
return 0;
}
二、🌵解题思路
1、性质归纳🍠
(1)、题目提示
2、输入输出🍅
(1)、输入:
- 图书数量:n
- 包邮条件(需要满足的最低阈值):x
- 第i本书的价格:a[1]、a[2]、a[3]……a[n]
(2)、求解:
- 求解满足包邮条件下的最少花费:即求一组i使得Min(∑ai) 且 (∑ai)>x
3、算法思路与求解步骤✌
a、分析:
- 目标:即求一组i使得Min(∑ai) 且 (∑ai)>x
- 抽象:即选部分物品,求和其价格和最小且满足>x
- 联想:许多物品,单个物品放与不放,联想至0/1背包问题
先前我写过的“0/1背包博文”:【动态规划法】0-1背包问题博文,点我即可直达哦~
b、结合此题的具体分析与步骤:
- 我的解法:回溯与分支限界法
- 回溯法专栏:【回溯法】专栏,点击我即可直达哦~
- 分支限界法专栏:【分支限界法】专栏,点击我即可直达哦~
c、代码过程:
c1、准备/算法依托媒介:
- 数组b[N]:其取值为0/1,表示第i本书有没有放入(第i本书的价格是否加入sum中)
- out: 即所求的“满足包邮条件下的最小花费”(因一直与其比较,如何取最小值,所以其初值需设置无穷大/尽量大)
c2、过程:
- 步骤一(代码中的
sort(a+1,a+n+1);//排序
):因为求解最小化问题,所以先排序(方便剪枝,在下述过程中会讲如何剪枝) - 步骤二前半段(代码bt中的第一个大if:
if(x>=m){//超出m,后续不需再算入
):将a[i],放入。若已放入的书本价格求和结果x>=m
,则后续的书本皆不需再进行判断.(假设此时放至第i本书),因为我们在步骤一进行排序,a[i+1]>=a[i]
(剪枝条件1) - 步骤二后半段:注意此时的
b[i]==0
(并没有放入,但是算入求和结果了,我复盘代码时愣了半天),先for循环找到放入第i本书之前已放入的书本序号:t_flag
,然后使b[t_flag]=0
(不放其),然后bt(t_flag+1,sum1);//不放a[t_flag],继续进行
(注意此时,sum1是没有算入第i和第t_flag价格,详见代码) - 步骤三前半段(放入i没有超出:
else{//未超出m
):for(int j=i+1;j<=n;j++) sum_sy+=a[j]; if(i!=n && sum_sy+sum1>=m) bt(i+1,sum1); //i未至n,并且剩余和+sum1可满足题意再继续
(剪枝条件2,即当前放入的书本后的(未遍历到的)所有的书本全放入所计算的价格和=sum<m,则不需要继续执行,这就是最后的30分剪枝,否则提交结果为70分哦) - 步骤三后半段(放入i以及后续所有书本还不够:
else{//i走到n还不够
):则同步骤二后半段继续进行遍历
❤️❤️❤️忙碌的敲代码也不要忘了浪漫鸭!
🔥静心复盘后呈现的博文,希望可以有点作用~
💕不知道我是否有讲懂呢,愿意的话可以评论区留言哦
🍅之前是不怎么吃肥肉的,后来,遇到了这里的猪脚饭~,味道真的很不错!
🌟别了三五天的雨;今,天终于放晴啦,最近也很开心,好不错好不错!