题解 AT1071 【haruki の覚醒め】

Chinshyo

2020-11-01 15:57:44

Solution

看完题面就知道是背包问题了。 # 题目分析 **题目中$ n $的数据不是特别的强,个人认为用递归的背包是更易懂的。** 求选数中大过 $ m $ 的最小的和。然而,我们就可以吧这里的和作为是背包里的物品体积。我们拿题目中样例举例: ![过程](https://cdn.luogu.com.cn/upload/image_hosting/t2ulhszr.png) 包的物品体积不得小于$ 30 $,更新时的条件比起传统的递归就要多增加这么一行语句: ```cpp if(sum>=m) ``` 这行代码就是控制背包体积不会小于 $ m $ 。 # 递归过程 我们在选数过程中用$ dep $来选举数列中的元素。分为两种情况:一种是取当前的,一种是不取当前的,所以就可以用这种代码表示: ```cpp dfs(dep+1,sum); if(sum+a[dep]<=ans) dfs(dep+1,sum+a[dep]); ``` 当中的剪枝条件纯粹是为了保证不$ T $的。~~其实我自己也担心递归的效率~~由于这道题没有直白的限制容积,所以不需要在这里考虑。 整个递归过程的代码: ```cpp void dfs(int dep,int sum) { if(dep>n) { if(sum>=m) { if(sum<ans) ans=sum; } } else { dfs(dep+1,sum); if(sum+a[dep]<=ans) dfs(dep+1,sum+a[dep]); } } ``` # 特殊情况 这道题有一种特殊情况,原题中:请输出最小且大于等于$ m $的,**若没有请输出$ -1 $**。所以在最后输出时要加一句: ```cpp if(ans!=INT_MAX) cout<<ans<<endl; else cout<<-1<<endl; ``` # AC 代码 ```cpp #include<bits/stdc++.h> using namespace std; int a[55],n,m,ans=INT_MAX; void dfs(int dep,int sum) { if(dep>n) { if(sum>=m) { if(sum<ans) ans=sum; } } else { dfs(dep+1,sum); if(sum+a[dep]<=ans) dfs(dep+1,sum+a[dep]); } } int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } dfs(1,0); if(ans!=INT_MAX) cout<<ans<<endl; else cout<<-1<<endl; return 0; } ```