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;
}