背包

Description

给定一个01背包和n个物品,求有多少种选择方法使得背包再也放不下余下的任意物品。

Input

第一行一个数字q,表示有q组测试数据 
对于每一组测试数据第一行有两个数字n和m,n表示物品的个数,m表示背包的体积,下一行中有n个数字V1…Vn分别表示每件物品的体积。

Output

一个数字,sum表示不能使背包再放入任何物品的方案数。(保证不大于int范围)

Sample Input

2
6 25
8 9 8 7 16 5
30 250
1 2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30

Sample Output

15
16509438

Hint

对于100%的数据,q≤1000,n≤30,m≤1000; 
对于每一个Vi,保证Vi≤1000;


【分析】

考虑到n很小。于是我们用枚举+Dp来A掉此题。

每次输入之后由小到大排序,然后开始枚举x。表示放不下x这个物品,又因为放不下x这个物品,所以1~x-1是一定能放进去的(已经排序)。于是我们用DP求出前x-1个都一定放进去之后,第x个放不下,后面的随便放的情况数。

f[j]表示恰好放了容积和为j的方案数。sum[]为排序后的前缀和数组。

的到状态转移方程:f[j]=sigma(f[j-V[i])  x+1<=i<=n,sum[x-1]+V[i]<=j<=m
边界:f[sum[x-1]]=1   因为前x-1个物品已经放进去了
ans=sigma(f[j])  m+1-V[x]<=j<=m

时间复杂度为O(T*(n^2)*m),严格的极限数据可能会超时,但是这个算法能够AC。


【代码】

/************************
    ID:Ciocio
	LANG:C++
	DATE:2013-12-23
	TASK:Bag
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define MAXN 35
#define MAXM 1005

int N,M,V[MAXN],f[MAXM],Sum[MAXN];

void _read(int &x)
{
	char tt=getchar();
	while(tt<'0'||'9'<tt) tt=getchar();
	for(x=0;'0'<=tt&&tt<='9';x=(x<<3)+(x<<1)+tt-'0',tt=getchar());
}

void _init()
{
	_read(N);_read(M);
	for(int i=1;i<=N;i++) _read(V[i]);
	sort(V+1,V+N+1);
	for(int i=1;i<=N;i++) Sum[i]=Sum[i-1]+V[i];
}

void _Dp(int x)
{
	memset(f,0,sizeof(f));
	f[Sum[x-1]]=1;
	for(int i=x+1;i<=N;i++)
		for(int j=M;j>=V[i]+Sum[x-1];j--)  //每个物品只有一个,DP时逆向扫描
			f[j]+=f[j-V[i]];
}

void _solve()
{
	int ans=0;
	for(int i=1;i<=N;i++)
	{
		if(Sum[i-1]>M) break;       //重要
		_Dp(i);
		for(int j=M+1-V[i];j<=M;j++) ans+=f[j];
	}
	cout<<ans<<endl;
}

int main()
{
	int Case;
	_read(Case);
	while(Case--)
	{
	    _init();
	    _solve();
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值