dfs與貪心演算法——洛谷5194

小明算法嘎嘎猛發表於2024-09-15

問題描述:
有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;
}


相關文章