题意
n个有体积的物品,问选取一些物品,且不能再继续选有多少方法?
n<=1000
题解
以前的考试题。当时是A了,但发现是数据水,POJ上WA了。
把体积从小到大排序枚举没选的物品中体积最小的。
假设枚举到i,那么1到i-1一定都选。可选的空间为[m-sum[i-1]+1,m]
然后对于后面的数跑DP的到f[i][j]前i个数空间恰好为j时的方案;
贡献为可选空间的方案。
一个优化是倒着枚举i,这样在求f[i][j]时所花费的时间会大大减少。
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 int sum[35],w[35]; 8 int dp[1005]; 9 int n, m, ans; 10 int main(){ 11 int cas, i, j, k, ca=1; 12 scanf("%d",&cas); 13 while(cas--){ 14 scanf("%d%d",&n,&m); 15 for(i=1;i<=n;i++) 16 scanf("%d",&w[i]); 17 sort(w+1,w+1+n); 18 printf("%d ",ca++); 19 if(w[1]>m){printf("0 ");continue;} 20 sum[0]=0; 21 for(i=1;i<=n;i++) 22 sum[i]=sum[i-1]+w[i]; 23 ans=0; 24 memset(dp,0,sizeof(dp)); 25 dp[0]=1; 26 for(i=n;i>=1;i--){ 27 for(j=max(0,m-sum[i-1]-w[i]+1);j<=m-sum[i-1];j++) 28 ans+=dp[j]; 29 for(j=m;j>=w[i];j--) 30 dp[j]+=dp[j-w[i]]; 31 } 32 printf("%d ",ans); 33 } 34 return 0; 35 }