問題描述:
有n個砝碼,將砝碼從大到小排列,從第三個砝碼開始,所有砝碼均大於其前兩個砝碼之和,問怎樣的砝碼組合才可以組合出不大於c的最大重量,輸出該重量
輸入:
第一行輸入兩個個整數N,c,代表有N個砝碼,第二行輸入N個砝碼的質量
輸出:
不大於c的最大重量
題目分析:
要找到不大於c的最大重量,要不斷逼近c,按貪心演算法來講,肯定是先拿最大的,然後在拿小的,因為小質量的砝碼更可以做到逼近而不超過,但這樣任然有很多組合,要找到最優的組合,可以利用dfs搜尋所有組合,仔細想想這種砝碼用了由於超過c而被捨棄的砝碼可能會被再次利用嗎,肯定可以再次利用,那麼理應使用vis標記,但我試了下把vis刪去居然也可以AC,我人傻了,難道所有的測試用例都可以貪心+暴力,不理解,但仔細想想好像也是,我們在迴圈部分,也是從大到小用砝碼的沒有回去用的。。。
#include<bits/stdc++.h>
using namespace std;
long long int n,c,ans=0,x;
long long int a[1999],summ[1999];
bool vis[1999];
void dfs(int cnt,long long int mm){
vis[cnt+1]=1;
//剪枝1:質量和不能大於c
if(mm>c)return;
//剪枝2:此時前面所有數之和還小於ans,也沒必要繼續搜尋了
if(mm+summ[cnt]<=ans)return;
if(ans<mm)ans=mm;//比較ans與現選數之和
if(mm+summ[cnt]<=c&&mm+summ[cnt]>=ans){
//此數之後全選的情況,與現ans比較
ans=mm+summ[cnt];
return;
}
//注意這裡的cnt會隨遞迴函式變化
for(int i=cnt;i>=1;i--){
if(vis[i]==0){
dfs(i-1,mm+a[i]);//正常的dfs ,從最大的砝碼開始增加
flag[i]=0;
}
}
}
int main(){
cin>>n>>c;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>c)break;//大於c的數不計入陣列
//記錄字首和
summ[i]=summ[i-1]+a[i];
//記錄使用砝碼數量
x++;
}
dfs(x,0);
cout<<ans;
return 0;
}