poj 3900 The Robbery (dfs+剪枝)

The Robbery
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 1517 Accepted: 134

Description

In the downtown of Bucharest there is a very big bank with a very big vault. Inside the vault there are N very big boxes numbered from 1 to N. Inside the box with number k there are k very big diamonds, each of weight Wk and cost Ck. 
John and Brus are inside the vault at the moment. They would like to steal everything, but unfortunately they are able to carry diamonds with the total weight not exceeding M. 
Your task is to help John and Brus to choose diamonds with the total weight less than or 
equal to M and the maximal possible total cost.

Input

The first line contains single integer T – the number of test cases. Each test case starts with a line containing two integers N and M separated by a single space. The next line contains N integers Wk separated by single spaces. The following line contains N integers Ck separated by single spaces.

Output

For each test case print a single line containing the maximal possible total cost of diamonds.

Sample Input

2 
2 4 
3 2 
5 3 
3 100 
4 7 1 
5 9 2

Sample Output

6 
29

Hint

Constraints: 
1 ≤ T ≤ 74, 
1 ≤ N ≤ 15, 
1 ≤ M ≤ 1000000000 (10 9), 
1 ≤ Wk, Ck ≤ 1000000000 (10 9).

Source


ps:这题很像完全背包   其实是完全背包  但是M、W、C数据太大  数组开不下   但是N的范围很小  所以想到dfs

思路:先按性价比排序,从前往后搜(按性价比),从大往小搜(按每种物品的个数)

然后就是两个剪枝了

剪枝1. 之后所有的钻石价值+目前已经得到的价值<=ans 则剪枝。

剪枝2. 剩下的重量全部装目前最高性价比的钻石+目前已经得到的价值<=ans 则剪枝。


感想:自己独立做其他都想到了  就是没想到要用剪枝1  还是TLE  看了峰峰的博客加了剪枝1才过的  每次都不能独立完成   ╮(╯﹏╰)╭

代码:

// Memory	184K   Time 1844MS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 20
using namespace std;

int n,m;
long long ans,wei;
long long sum[maxn];
struct Node
{
    long long w,v;
    int num;
    double r;
}node[maxn];

bool cmp(const Node &x1,const Node &x2)
{
    return x1.r>x2.r;
}
void dfs(int pos,long long ww,long long val)   // 当前节点 剩余重量 价值
{
    int i,j,flag=0;
    if(ans<val) ans=val;
    if(pos>n||ans>=ww*node[pos].r+val||ans>=val+sum[pos]) return ;    // 剪枝
    for(i=node[pos].num;i>=1;i--)
    {
        if(pos==n&&flag) break ;
        if(ww>=node[pos].w*i)
        {
            flag++;
            dfs(pos+1,ww-node[pos].w*i,val+node[pos].v*i);
        }
    }
    dfs(pos+1,ww,val);
}
int main()
{
    int i,j,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%lld",&n,&wei);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&node[i].w);
        }
        for(i=1;i<=n;i++)
        {
            node[i].num=i;
            scanf("%d",&node[i].v);
            node[i].r=node[i].v*1.0/node[i].w;
        }
        sort(node+1,node+n+1,cmp);      // 按性价比排序
        memset(sum,0,sizeof(sum));      // 预处理sum-后面的所有钻石总价值
        for(i=n;i>=1;i--)
        {
            sum[i]=sum[i+1]+node[i].num*node[i].v;
        }
        ans=0;
        dfs(1,wei,0);
        printf("%lld\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值