原题: http://acm.hdu.edu.cn/showproblem.php?pid=5234
题目:
Happy birthday
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 686 Accepted Submission(s): 312
Problem Description
Today is Gorwin’s birthday. So her mother want to realize her a wish. Gorwin says that she wants to eat many cakes. Thus, her mother takes her to a cake garden.
The garden is splited into n*m grids. In each grids, there is a cake. The weight of cake in the i-th row j-th column is wij kilos, Gorwin starts from the top-left(1,1) grid of the garden and walk to the bottom-right(n,m) grid. In each step Gorwin can go to right or down, i.e when Gorwin stands in (i,j), then she can go to (i+1,j) or (i,j+1) (However, she can not go out of the garden).
When Gorwin reachs a grid, she can eat up the cake in that grid or just leave it alone. However she can’t eat part of the cake. But Gorwin’s belly is not very large, so she can eat at most K kilos cake. Now, Gorwin has stood in the top-left grid and look at the map of the garden, she want to find a route which can lead her to eat most cake. But the map is so complicated. So she wants you to help her.
Input
Multiple test cases (about 15), every case gives n, m, K in a single line.
In the next n lines, the i-th line contains m integers wi1,wi2,wi3,⋯wim which describes the weight of cakes in the i-th row
Please process to the end of file.
[Technical Specification]
All inputs are integers.
1<=n,m,K<=100
1<=wij<=100
Output
For each case, output an integer in an single line indicates the maximum weight of cake Gorwin can eat.
Sample Input
1 1 2
3
2 3 100
1 2 3
4 5 6
Sample Output
0
16
Hint
In the first case, Gorwin can’t eat part of cake, so she can’t eat any cake.
In the second case, Gorwin walks though below route (1,1)->(2,1)->(2,2)->(2,3). When she passes a grid, she eats up the cake in that grid. Thus the total amount cake she eats is 1+4+5+6=16.
思路:
从左上角出发,走到右下角,每次可以向右或者向下走,走过的地方有蛋糕数量,求不超过指定数量的最大值。
如果只能向右走或者向下走,那么这是个01背包。
现在可以向右和向下,其实也是个01背包。
三维数组dp[i][j][k],其中ij分别表示坐标,k表示当前当前背包容量,dp值为真表示满足从原点到ij装k个蛋糕的情况,dp值为假则表示不满足。
状态转移方程:dp[i][j][k]=max(max(dp[i-1][j][k],dp[i-1][j][k-a[i][j]]+a[i][j]),max(dp[i][j-1][k],dp[i][j-1][k-a[i][j]]+a[i][j]))
和普通的转移方程相比,它只是比较了两个方向而已。
代码:
//
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=105;
int a[N][N]; //重量
int dp[N][N][N]; //加入到xy位置背包容量为z情况下的总重量,即为记录的最优解
void init()
{
memset(dp,0,sizeof(dp));
}
void gao(int n,int m,int v)
{
for(int i=a[0][0]; i<=v; ++i)
{
dp[0][0][i]=a[0][0];
}
for(int i=1; i<n; ++i) //从头向下遍历
{
for(int j=0; j<=v; ++j) //j当前容量
{
if(j<a[i][0]) //装不下当前物品
dp[i][0][j]=dp[i-1][0][j]; //最优解即为不装本次的情况,即上次的情况
else
dp[i][0][j]=max(dp[i-1][0][j],dp[i-1][0][j-a[i][0]]+a[i][0]); //装得下,上次最优解和放入的最优解
}
}
for(int i=1; i<m; ++i) //从头向右遍历
{
for(int j=0; j<=v; ++j)
{
if(j<a[0][i])
dp[0][i][j]=dp[0][i-1][j];
else
dp[0][i][j]=max(dp[0][i-1][j],dp[0][i-1][j-a[0][i]]+a[0][i]);
}
}
for(int i=1; i<n; ++i) //向右下双向打表
{
for(int j=1; j<m; ++j)
{
for(int k=0; k<=v; ++k)
{
if(k<a[i][j])
dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k]);
else
dp[i][j][k]=max(max(dp[i-1][j][k],dp[i-1][j][k-a[i][j]]+a[i][j]),max(dp[i][j-1][k],dp[i][j-1][k-a[i][j]]+a[i][j]));
}
}
}
printf("%d\n",dp[n-1][m-1][v]);
}
int main()
{
int n,m,k;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
init();
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
scanf("%d",&a[i][j]);
gao(n,m,k);
}
return 0;
}