lightoj1200 【完全背包】

题意:
有一个能放W重的袋子,然后妻子给了老公一列清单,每个item会有价格,数量,重量。
首先得满足老婆的要求,然后在可装的地方输出最大还能拿多少使得拿的东西的钱最多。
注意标题是thief,我想大家也能知道基本上出背包题的人都是心机biao啊…)逃
思路:
1.首先要满足wife的要求是不是。
2.其次再满足husband的小心思。
后面就转化成了完全背包。

一开始类似0/1背包直接那个超时转化交了一发,肯定T。。
)然后贴了一发完全背包模板就过了。。。

——然后去看了百度百科的完全背包(没错就是百度百科),摘了几句下来

完全背包与01背包的伪代码只有v的循环次序不同而已。为什么这样一改就可行呢?

因为要保证第i次循环中的状态dp[ j ]是由状态dp[ j-w[ i ] ]递推而来。
换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个没有已经选入第i件物品的子结果dp[ j - w[ i ] ]。
比如当你在算dp[ j(>2*w[i]) ] 的时候,其实你的dp[j-w[i]]在前面已经更新了,所以采用一维数组直接可以办到,而且每次更新的复杂度是O(W),总的来说就是O(nW);
这也是最优解法吧。
不过百度百科上还有一个优化没怎么看懂。
原文:
更高效的转化方法是:把第i种物品拆成费用为c*2^k、价值为w*2^k的若干件物品,其中k满足0<=k<=log2(V/c)+1。这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。这样把每种物品拆成O(log2(V/c))件物品,是一个很大的改进。
wonter巨:因为一个数总能分成若干个2^i相加之和啊。
也许这样可以若有所思~
code…

#include<bits/stdc++.h>
//#include<cstdio>
//#include<math.h>
//#include<string.h>
//#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const double eps=1e-5;
const double pi=acos(-1.0);
const int mod=1e8+7;
const LL INF=0x3f3f3f3f;

const int N=1e2+10;

int val[N],dw[N];
int dp[N*N];

int main()
{
    int cas=1;
    int n,w;
    int t,x,sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&w);
        sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&val[i],&x,&dw[i]);
            sum+=x*dw[i];
        }
        w-=sum;
        if(w<0){
            printf("Case %d: Impossible\n",cas++);
            continue;
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            for(int j=dw[i];j<=w;j++){
                dp[j]=max(dp[j],dp[j-dw[i]]+val[i]);
            }
        }
        printf("Case %d: %d\n",cas++,dp[w]);
    }
    return 0;
}
posted @ 2016-07-25 10:30  see_you_later  阅读(123)  评论(0编辑  收藏  举报