POJ3093 Margaritas on the River Wal ( 背包DP)

53 篇文章 0 订阅
51 篇文章 1 订阅

POJ3093 Margaritas on the River Walk

原题地址http://poj.org/problem?id=3093

题意:
T组数据,每次给定N个物品的价格和总的钱数,每种物品只能选一次,求共有多少种方案,使之不能再装下任一物品。

数据范围
T<=1000,N<=30,M<=1000

题解:
(好题)

因为要求背包不能再装的方案数,不能再装即=最小的也装不进去
于是,为了避免统计重复方案,枚举不在背包中最小的物品。那么比他小的物品必然全部在背包中,这时用剩下的容积v对比他大的物品做背包,统计方案,则此时的方案是f[v-w[i]+1]~f[v]的方案数之和。
这样的复杂度是O(TMN^2)
考虑原本做背包的过程,外面一层循环是物品,里面是容积,
那么我们实际不需要做N次背包,只需从大到小地向背包中添加物品,每次添加前如上述方式统计方案数即可。
总复杂度O(TNM)

(关键点倒不是这个优化,是如何由“判重的标准”想到“枚举不在背包中的最小物品”,这个转点在于”不能再装“意味着最小的也装不进去。)
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=1005;
const int inf=0x3f3f3f3f;
int T,n,m,sum[N],f[N],w[N];
int main()
{
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        memset(f,0,sizeof(f));
        memset(sum,0,sizeof(sum));
        f[0]=1;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        sort(w+1,w+n+1);
        if(w[1]>m) {printf("%d 0\n",t); continue;}
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+w[i]; 
        int ans=0;
        for(int i=n;i>=1;i--)
        {
            if(m-sum[i-1]>=0)
            {
                int st=max(m-sum[i]+1,0); 
                for(int j=st;j<=m-sum[i-1];j++)
                ans+=f[j];  
            }
            for(int j=m;j>=w[i];j--) f[j]+=f[j-w[i]];       
        }
        printf("%d %d\n",t,ans);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值