题目链接:http://poj.org/problem?id=3093
题目大意:给定一个容量为V(题目里是D)的背包和N(题目里是V)件物品各自的体积,求有多少种方法使得背包再也装不下任何物品。
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
假设所有物品按照从小到大排序,枚举剩下物品的最小体积,则前面的所有物品都被放入背包,当前的背包空余为v-sum[i],而为了挤占掉所枚举的物品的空间,那么我们就需要最小体积为v-sum[i]-a[i]+1的物品,最大为v-sum[i]的物品。我们将这个范围内的物品体积的方案数直接加到总的ans中就行了,接下来就是物品体积方案数的转移,dp[j]表示空间为j的可以又几个方向转移过来。那么dp[j]=d[j]+dp[j-a[i]]。
以下是AC代码:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int mac=1e3+10; int dp[mac],a[mac]; bool cmp(int x,int y){return x>y;} int main() { int t,n,m,test=0; scanf ("%d",&t); while (t--){ int tot=0; scanf ("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf ("%d",&a[i]),tot+=a[i]; sort(a+1,a+1+n,cmp); test++; if (a[n]>m) {printf("%d 0 ",test);continue;} memset(dp,0,sizeof dp); dp[0]=1; int ans=0; for (int i=1; i<=n; i++){//枚举剩下的最小a[i] tot-=a[i];//tot的当前值 int st=max(0,m-tot-a[i]+1);//m-tot,剩余空间,不让a[i]入包所需要占据的最小空间 for (int j=st; j<=m-tot; j++)//占据a[i]的空间 ans+=dp[j]; for (int j=m; j>=a[i]; j--)//空间为j的大小可以由几个方向转移过来 dp[j]+=dp[j-a[i]]; } printf("%d %d ",test,ans); } return 0; }