题目描述
链接:https://ac.nowcoder.com/acm/problem/16759
来源:牛客网
设有N*N的方格图(N ≤ 10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):
某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
题目思路
因为是走两次,所以根据动态规划的思想,可以认为是两个人同时走。因此可以用四维数组dp[i][j][k][p]来表示两个人到到当前位置时的取数之和。其中,(i,j) 表示第一个人的位置;(k,p)表示第二个人的位置。
由于每个人的走到当前位置的可能性有两种,所以组合起来就有四种构成dp[i][j][k][p]的方式,状态转移方程如下:
dp[i][j][k][p] = max(max(dp[i-1][j][k-1][p], dp[i][j-1][k-1][p]), max(dp[i-1][j][k][p-1], dp[i][j-1][k][p-1])) + a[i][j] + a[k][p];
有可能这两个人走到了同一个位置,此时该位置上的数只用被记录一遍:
dp[i][j][k][p] = max(max(dp[i-1][j][k-1][p], dp[i][j-1][k-1][p]), max(dp[i-1][j][k][p-1], dp[i][j-1][k][p-1])) + a[i][j];
由于是利用四重循环得到的dp数组,所以每一种路径重复的情况都会在循环时被计算过,因此不必再进行置零处理。
完整代码
#include<bits/stdc++.h>
using namespace std;
int a[15][15] = {0};
int dp[15][15][15][15];
int main()
{
int n;
scanf("%d",&n);
int i = n;
while(1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x+y+z!=0)
a[x][y] = z;
else break;
}
dp[1][1][1][1] = a[1][1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
for(int p=1;p<=n;p++)
{
if(i==k && j==p)
dp[i][j][k][p] = max(max(dp[i-1][j][k-1][p], dp[i][j-1][k-1][p]), max(dp[i-1][j][k][p-1], dp[i][j-1][k][p-1])) + a[i][j];
else
dp[i][j][k][p] = max(max(dp[i-1][j][k-1][p], dp[i][j-1][k-1][p]), max(dp[i-1][j][k][p-1], dp[i][j-1][k][p-1])) + a[i][j] + a[k][p];
}
}
}
}
printf("%d\n",dp[n][n][n][n]);
return 0;
}总结
刚开始的思路是利用贪心,先求出一条和最大的路径,更新a地图,再重新遍历取得另一条最大路径。虽然样例过了,但是还是不能通过全部测试用例。这种情况应该引以为戒,再出现这种多次求极值的问题时,应该综合起来考虑,通过一次动归完成。
不过从错误的想法中我又复习了怎样通过dp方程还原路径,所以代码附下:
#include<bits/stdc++.h>
using namespace std;
long long dp[15][15];
int main()
{
int n;
int grid[15][15] = {0};
long long ans = 0;
scanf("%d",&n);
while(1)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a+b+c)
{
grid[a][b] = c;
}
else break;
}
dp[1][1] = grid[1][1];
for(int i=2;i<=n;i++)
{
dp[i][1] = dp[i-1][1] + grid[i][1];
dp[1][i] = dp[1][i-1] + grid[1][i];
}
for(int i=2;i<=n;i++)
{
for(int j=2;j<=n;j++)
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + grid[i][j];
}
}
int ok=0;
int x = n, y = n;
while(!ok)
{
grid[x][y] = 0;
//printf("(%d, %d)\n",x,y);
if(x>1 && y>1 && dp[x-1][y] >= dp[x][y-1] )
{
x = x-1;
y = y;
}
else if(x>1 && y>1 && dp[x-1][y] < dp[x][y-1])
{
x = x;
y = y-1;
}
else if(x == 1)
{
for(int i=y;i>0;i--)
{
grid[1][i] = 0;
}
ok = 1;
break;
}
else if(y == 1)
{
for(int i=x;i>0;i--)
{
grid[i][1] = 0;
}
ok = 1;
break;
}
if(x == 1&&y == 1)
{
ok = 1;
grid[1][1] = 0;
break;
}
}
ans = dp[n][n];
memset(dp, 0, sizeof(dp));
for(int i=2;i<=n;i++)
{
dp[i][1] = dp[i-1][1] + grid[i][1];
dp[1][i] = dp[1][i-1] + grid[1][i];
}
for(int i=2;i<=n;i++)
{
for(int j=2;j<=n;j++)
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + grid[i][j];
}
}
ans = ans + dp[n][n];
printf("%lld\n", ans);
return 0;
}


京公网安备 11010502036488号