dfs与贪心算法——洛谷5194

问题描述:
有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;
}


posted @ 2024-09-15 20:25  小明算法嘎嘎猛  阅读(1)  评论(0编辑  收藏  举报