Description

One of the more popular activities in San Antonio is to enjoy margaritas in the park along the river know as the River Walk. Margaritas may be purchased at many establishments along the River Walk from fancy hotels to Joe’s Taco and Margarita stand. (The problem is not to find out how Joe got a liquor license. That involves Texas politics and thus is much too difficult for an ACM contest problem.) The prices of the margaritas vary depending on the amount and quality of the ingredients and the ambience of the establishment. You have allocated a certain amount of money to sampling different margaritas.

Given the price of a single margarita (including applicable taxes and gratuities) at each of the various establishments and the amount allocated to sampling the margaritas, find out how many different maximal combinations, choosing at most one margarita from each establishment, you can purchase. A valid combination must have a total price no more than the allocated amount and the unused amount (allocated amount – total price) must be less than the price of any establishment that was not selected. (Otherwise you could add that establishment to the combination.)

For example, suppose you have $25 to spend and the prices (whole dollar amounts) are:

Vendor A B C D H J
Price 8 9 8 7 16 5

Then possible combinations (with their prices) are:

ABC(25), ABD(24), ABJ(22), ACD(23), ACJ(21), ADJ( 20), AH(24), BCD(24), BCJ(22), BDJ(21), BH(25), CDJ(20), CH(24), DH(23) and HJ(21).

Thus the total number of combinations is 15.

Input

The input begins with a line containing an integer value specifying the number of datasets that follow, N (1 ≤ N ≤ 1000). Each dataset starts with a line containing two integer values V and D representing the number of vendors (1 ≤ V ≤ 30) and the dollar amount to spend (1 ≤ D ≤ 1000) respectively. The two values will be separated by one or more spaces. The remainder of each dataset consists of one or more lines, each containing one or more integer values representing the cost of a margarita for each vendor. There will be a total of V cost values specified. The cost of a margarita is always at least one (1). Input values will be chosen so the result will fit in a 32 bit unsigned integer.

Output

For each problem instance, the output will be a single line containing the dataset number, followed by a single space and then the number of combinations for that problem instance.

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

1 15
2 16509438

 

【题意】给出n件物品的体积以及背包的体积,求多少种背包再也放不下东西的方法。

【思路】现将物体的体积排序,定义一个数组第i件放不下,存储前i-1的体积和sum[i-1];用dp[i]表示体积为i的时候有dp[i]种再也放不下东西的方法,

则,假设第i件放不下,则前i-1件是能放下的,当v-sum[i-1]-vol[i]+1~v-sum[i-1](v-sum[i-1]-vol[i]+1可能会小于0,这时与0取大者),

如果从体积小的物品开始枚举,考虑当第i件物品不能放入背包的情况,此时,前i-1件物品就都已经被放到背包里面去了,

那么就需要计算第i+1 ~ n件物品占据体积tmp ~ V-sum[i-1]的方法数,然后再在总方法数上加上dp数组对应的值。

那么,第i件物品就被考虑了i-1次,此时的算法复杂度为O(N^2 * V)。

为了使得每件物品只被放入到背包一次,考虑从体积大的物品开始枚举。当第i件物品不能放入背包中,而前i件物品都放入了背包中,

这时,我们把已知的i+1 ~ N件物品占据体积k ~ V-sum[i-1]的方法数加到总的方法数ans上,然后再去取第i件物品做01背包,供考虑下一件物品不能放入背包的情况使用,直到枚举完全部的物品。

在逆序枚举的时候,当第i件物品放不下的时候,第i件物品后的物品都被考虑过了,且第i件物品之后的物品也肯定放不下。

而顺序枚举的话,第i件物品之前的物品都被考虑过作为当前放不下的最小物品了,第i件物品放不下不意味着前面被考虑过的i-1件物品放不下,

这就违背我们当初的假设了,如果这么做了,还有装进背包的物品的方法就也被考虑进去了。

参考:http://www.cnblogs.com/zhexipinnong/archive/2012/11/16/2772498.html

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1005;
int dp[N],sum[N],vol[N];
int n,v;
int main()
{
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&v);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&vol[i]);
        }
        sort(vol+1,vol+1+n);
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        dp[0]=1;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+vol[i];
        }
        for(int i=n;i>=1;i--)
        {
            int tmp=max(0,v-sum[i-1]-vol[i]+1);
            for(int j=v-sum[i-1];j>=tmp;j--)
            {
                ans+=dp[j];
            }
            for(int j=v;j>=vol[i];j--)
            {
                dp[j]+=dp[j-vol[i]];
            }
        }
        if(vol[1]>v) ans=0;
        printf("%d %d\n",cas++,ans);
    }
    return 0;
}