题解 P1049 【装箱问题】
这题拿到手我就想着可不可以枚举,但没多久就发现这样会超时。
由于DP我还不会,所以作为一支konjac的我就用一种叫做记忆化搜索的与DP雷同但实现较简单的算法。
于是,我记dfs(x,y)表示选取前x个箱子,容量为y时装入箱子的最大体积。
所以如果y+a[x]<=n,就表示第x个箱子可以装进去,那么装进去后的最大值就是dfs(x+1,y+a[i])
而每一种情况,第x个箱子都可以不装入所以不装入的最大值为dfs(x+1,y)
所以dfs(x,y)=max(dfs(x+1,y),s)
其中若y+a[x]<=n,s=dfs(x+1,y+a[i]) 否则s=0
但这只是普通的搜索,为了达成"记忆化"我们就要开一个f二维数组来记录已经搜索过的状态。
f数组初始值为-1,在进行dfs(x,y)时若f[x][y]!=-1那就说明这一状态已经被搜索过,直接返回f[x][y]即可。
否则就搜索,在最后返回值之前将搜索到的值存入f数组中。
这样我们就完成了一个记忆化搜索的过程。
下面上AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int v,n,a[35],f[35][20005];
inline int max(int x,int y){return x>y?x:y;}
inline int dfs(int x,int y){
if(x==n+1) return y;
if(f[x][y]!=-1) return f[x][y];
int xx=0,yy=dfs(x+1,y);
if(y+a[x]<=v) xx=dfs(x+1,y+a[x]);
f[x][y]=max(xx,yy);
return f[x][y];
}
int main(){
scanf("%d",&v); scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<=v;j++)
f[i][j]=-1;
printf("%d\n",v-dfs(1,0));
return 0;
}