首先,题目已经可以明确的第一思路是使用暴力枚举所有的选择情况,然后得到包邮情况下的最小值即可
#include<bits/stdc++.h> using namespace std; int n, x; int Min = 999999; vector<int> book; int visit[35] = { 0 }; //访问数组 void DFS(int sum, int t) { if (sum >= x) //满足包邮条件就记录一次 { Min = min(Min, sum); //找最小值 return; } for (int i = t; i < book.size(); i++) //从book[0]开始,遍历所有可能组合 { if (visit[i] == 0) { visit[i] = 1; DFS(sum + book[i], i); //没访问过就sum加和继续递归调用 visit[i] = 0; //组合后重置访问数组为0 } } } int main() { cin >> n >> x; int y; for (int i = 0; i < n; i++) { cin >> y; book.push_back(y); } DFS(0, 0); cout << Min << endl; return 0; }
需要强调的是,这里在DFS里面的for循环一定要从t开始,否则暴力都拿不了多少分,因为这样既可以保证选择不会重叠又可以保证多余的遍历
思路2:转换为01背包问题
对背包问题比较熟悉的同学可能一眼就看出类背包了,我们知道经典的背包问题是在有限的空间内,选择一些物品使得物品的总价值最大。
而该题 是在满足包邮条件下(可以看作 选择的物品总重量>=x 的条件下),选择最小的价值,同时该题的重量与价值是一样的
可以理解为
在选择的物品总重量在<sum-x的条件下,选择最大的价值
#include<iostream> #include<algorithm> using namespace std; int n,x; int book[35]; int dp[35][300005];//dp[i][j]表示在前i本书,选择要除去的书,当前购物车为j元的 满足包邮条件的花费 int main(){ int sum=0;//最大价格 cin>>n>>x; for(int i=1;i<=n;i++){ cin>>book[i]; sum+=book[i]; } int res=sum;//满足条件的最低价格 for(int i=1;i<=n;i++){ for(int j=1;j<=sum;j++){ if(book[i]<=j){//当前背包还可以装 就选择最大情况即可 dp[i][j]=max(dp[i-1][j],dp[i-1][j-book[i]]+book[i]); }else{//空间不够了 此时不装 dp[i][j]=dp[i-1][j]; } if(x<=dp[i][j]&&dp[i][j]<res){ res=dp[i][j];//得到满足条件的最小值 } } } cout<<res<<endl; return 0; }