POJ 3900 The Robbery(dfs)

125 篇文章 0 订阅

Description
一个劫匪带着一个可装m重量的超大背包去抢银行,银行有n个大箱子,第i个箱子里有i个重量为wi,价值为ci的大钻石,问该劫匪抢走钻石的最大价值
Input
第一行为一整数T表示用例组数,每组用例第一行为两个整数n和m分别表示钻石个数和背包可装钻石重量上限,第二行为n个整数wi表示第i箱子中每颗钻石的重量,第三行为n个整数ci表示第i箱子中每颗钻石的价值
(1<=T<=74,1<=n<=15,1<=wi,ci,m<=1e9)
Output
对于每组用例,输出该劫匪带走钻石的最大价值
Sample Input
2
2 4
3 2
5 3
3 100
4 7 1
5 9 2
Sample Output
6
29
Solution
此题咋一看以为是01背包,看到背包容量以为是超大背包,但物品个数太多,所以只能用dfs了,而搜索中需要注意几点,首先是先将所有钻石的性价比降序排,每次优先选择性价比高的钻石,而且选择这种钻石的数量也要从高到低枚举搜索,同时有两步重要剪枝:
设当前已经选到第pos种钻石,背包剩余容量为left,已经选取的钻石重量为sum,最优解为ans
剪枝一:
sum+left*c[pos]/w[pos] < ans,说明就算将背包剩余容量全部放当前这种性价比最高的钻石也没有已经达到的最优解大的话停止搜索
剪枝二:
sum+sum(c[pos]*cnt[pos]+c[pos+1]*cnt[pos+1]+…+c[n]*cnt[n]) < ans,说明就算将剩余钻石全部拿上也没有已经达到的最优解大的话停止搜索
剪枝三:
枚举当前钻石数量i时,left < w[pos]*i,说明背包容量已经不够,无需继续搜索,继续下一次枚举即可
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int t,n,m;
ll ans,d_sum[22];
struct node
{
    ll w,c;//钻石重量以及价值 
    double wc;//钻石性价比 
    int cnt;//钻石数量 
}d[22];
int cmp(node a,node b)//将钻石按性价比降序排 
{
    return a.wc>b.wc;
}
void dfs(int pos,ll sum,ll left)
{
    ans=max(ans,sum);//更新最优解 
    if(pos>=n||left==0)return ;//搜索完毕 
    if(sum+left*d[pos].wc<=ans)return ;//剪枝一 
    if(sum+d_sum[pos]<=ans)return ;//剪枝二 
    for(int i=d[pos].cnt;i>=0;i--)//注意枚举次序,数量由高到低枚举 
    {
        if(left-d[pos].w*i<0)continue;//剪枝三 
        dfs(pos+1,sum+d[pos].c*i,left-d[pos].w*i);//深搜 
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%lld",&d[i].w),d[i].cnt=i+1; 
        for(int i=0;i<n;i++)scanf("%lld",&d[i].c),d[i].wc=1.0*d[i].c/d[i].w;
        d_sum[n]=0;
        for(int i=n-1;i>=0;i--)//统计后缀钻石总价值 
            d_sum[i]=d_sum[i+1]+d[i].c*d[i].cnt;        
        sort(d,d+n,cmp);//排序 
        ans=0;
        dfs(0,0,m);
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值