题解:P2409 Y的积木
现存的题解似乎没有用 dp 做的,来补一发。
Solution P2409
Idea
我们设 为现在考虑到了第 盒积木,总重量为 的方案数。
那么很显然有 ,其中 表示这一盒积木中的第几块, 表示第 盒第 块积木的重量。
最后统计答案的时候,从小到大枚举,对于每一个可行方案让计数器加一,然后判断是否比 大即可。如果这一段比较抽象,文末会放统计答案的代码。
这样转移的代码就长这样:
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m[i];j++){
for(int k=a[i][j];k<=maxw;k++){
dp[i][k]=dp[i][k]+dp[i-1][k-a[i][j]];
}
}
}
但是它会 WA 掉最后一组 hack 数据。
我们考虑一下,当 且全部 时,若所有重量全部相同,则会出现方案数过多而爆 long long 的情况。
那么我们想,最多会有 个答案,那么我们只需要把 保存到最大值为 ,就可以满足所有情况了。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=105,maxw=10000;
int n,m[N],a[N][N],kk;
int dp[N][N*N];
int main(){
scanf("%d%d",&n,&kk);
for(int i=1;i<=n;i++){
scanf("%d",&m[i]);
for(int j=1;j<=m[i];j++){
scanf("%d",&a[i][j]);
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m[i];j++){
for(int k=a[i][j];k<=maxw;k++){
dp[i][k]=min(kk,dp[i][k]+dp[i-1][k-a[i][j]]);//最核心的部分:保存到最大值为 k(代码中为 kk)。
}
}
}
int cnt=0;
for(int i=0;i<=maxw;i++){
for(int j=1;j<=dp[n][i];j++){
cnt++;
printf("%d ",i);
if(cnt==kk)return 0;
}
}
return 0;
}
Time
显然转移是 的(其中 为最大重量)。最大重量显然是 的最大值,这个值是 。
所以不会超时,但是复杂度也很高。

浙公网安备 33010602011771号