POJ

来源:互联网 发布:数据库审计产品排名 编辑:程序博客网 时间:2024/06/07 14:06

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).

W,C值很大,数组开不下,但是发现N值很小,(1+15)*15/2=120,所以可以考虑dfs+剪枝。TLE一下午才憋出来。

首先利用贪心的思想我们对箱子进行排序,关键字为性价比(参考了poj里的discuss)。

也就是单位重量的价值最高的排第一,搜索的时候枚举顺序注意一定要从满到空,这样才能最快的找到一个可行解然后利用它进行接下来的剪枝。


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

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

#include <iostream>#include <algorithm>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <string.h>#include <map>#include <set>#include <queue>#include <deque>#include <list>#include <bitset>#include <stack>#include <stdlib.h>#define lowbit(x) (x&-x)#define e exp(1.0)//ios::sync_with_stdio(false);//    auto start = clock();//    cout << (clock() - start) / (double)CLOCKS_PER_SEC;typedef long long ll;typedef long long LL;using namespace std;const int maxn=20;struct node{    ll w,v;    int num;}b[maxn];int n;ll m,ans,sum[maxn];//保存一个后缀和int cmp(const node &a,const node &b){    return a.v*1.0/a.w > b.v*1.0/b.w;}bool cut(int pos,ll now_v,ll last_w){    if(pos>n) return true;//返回条件    if(now_v+sum[pos]<ans) return true;    double best=b[pos].v*1.0/b[pos].w;    if((now_v+(ll)(ceil)(best*last_w))<ans) return true;    return false;}void dfs(int pos,ll now_v,ll last_w)//pos为当前数组的下标位置,目前价值和,剩余容量{    ans=max(ans,now_v);    if(cut(pos,now_v,last_w))return ;    for(int i=b[pos].num;i>=0;--i)//枚举每一个盒子,满->空    {        if(last_w<b[pos].w*i) continue;        dfs(pos+1,now_v+b[pos].v*i,last_w-b[pos].w*i);    }}int main(){    int T;    cin>>T;    ll sumv,sumw;    while(T--)    {        memset(sum,0,sizeof(sum));        ans=0;        sumv=sumw=0;        cin>>n>>m;        for(int i=1;i<=n;i++)            cin>>b[i].w,sumw+=b[i].w*i;        for(int i=1;i<=n;i++)            cin>>b[i].v,b[i].num=i,sumv+=b[i].v*i;        if(sumw<=m)        {            cout<<sumv<<endl;            continue;        }        sort(b+1,b+1+n,cmp);        sum[n]=b[n].v*b[n].num;        for(int i=n-1;i>0;i--)//计算后缀和            sum[i]=sum[i+1]+b[i].v*b[i].num;        dfs(1,0,m);        cout<<ans<<endl;    }    return 0;}