题目描述
设有 N×N 的方格图 (N≤9) ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0 。如下图所示(见样例):
0 0 0 0 0 0 0 0
0 0 13 0 0 6 0 0
0 0 0 0 7 0 0 0
0 0 0 14 0 0 0 0
0 21 0 0 0 4 0 0
0 0 15 0 0 0 0 0
0 14 0 0 0 0 0 0
0 0 0 0 0 0 0 0
某人从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0 )。
此人从 A 点到 B 点共走两次,试找出 2 条这样的路径,使得取得的数之和为最大。
输入输出格式
输入格式:
输入的第一行为一个整数 N (表示 N×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 0 表示输入结束。
输出格式:
只需输出一个整数,表示 2 条路径上取得的最大的和。
输入输出样例
输入样例#1: 复制
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
输出样例#1: 复制
67
一开始想当然的认为2 条路径上取得的最大的和等于第一次路径最大和加上取点后第二次路径最大和,结果WA了,只有80分。错的那个测试点是:
7
1 3 2
1 4 3
2 3 3
3 3 3
5 5 4
6 5 4
7 3 2
7 5 4
0 0 0
程序输出是23,而正确答案是25。错的原因是23=20(第一次最大值)+3(第二次最大值),25=19(并不是第一次最大值)+5(第二次最大值)。也就是说一开始的想法错了。
先附上80分代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<stack>
using namespace std;
int Map[10][10];//方格上的数
int dp[10][10];//dp[i][j]表示从Map[1][1]到Map[i][j]的最大路径和
bool path[10][10];//要取出数的方格置为1
int N;
bool flag=0;
void recur()
{
memset(dp,0,sizeof(dp));
dp[1][1]=Map[1][1];
for(int j=2;j<=N;j++)
dp[1][j]=dp[1][j-1]+Map[1][j];
for(int i=2;i<=N;i++)
dp[i][1]=dp[i-1][1]+Map[i][1];
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])+Map[i][j];
}
int sum;
void anti_recur(int i,int j)
{
if(i==1&&j==1)
{
if(sum==Map[1][1])flag=1;
path[i][j]=1;
return;
}
if(sum==Map[i][j]+dp[i][j-1])
{
path[i][j]=1;sum-=Map[i][j];
anti_recur(i,--j);
if(flag) return;
path[i][j]=0;sum+=Map[i][j];
}
else if(sum==Map[i][j]+dp[i-1][j])
{
path[i][j]=1;sum-=Map[i][j];
anti_recur(--i,j);
if(flag) return;
path[i][j]=0;sum+=Map[i][j];
}
}
int main()
{
int x,y,num,ans=0;
cin>>N;
memset(Map,0,sizeof(Map));
while(cin>>x>>y>>num,x!=0&&y!=0&&num!=0)
{Map[x][y]=num;}
recur();//第一次求出最大路径和为dp[N][N]
ans+=dp[N][N];
memset(path,0,sizeof(path));
sum=dp[N][N];
anti_recur(N,N);//将要取出数的方格求出来
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(path[i][j]&&Map[i][j]) Map[i][j]=0;//取走第一次经过方格的数
recur();//递推,第二次求出最大路径和为dp[N][N]
ans+=dp[N][N];
cout<<ans;
}
后开看了下题解,了解到这题是四维动规的模板题(生无可恋.jpg)用dp[i][j][k][l]表示两个人分别从Map[1][1]走到Map[i][j]和Map[k][l]的最大路径和,显然,这题最后的结果是dp[N][N][N][N],注意的是如果两个人走到相同格子,则最大路径和要减去相同格子里面的数,因为其被计算了两遍。
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<stack>
using namespace std;
int N;
int Map[10][10];
int dp[10][10][10][10];
int main()
{
int x,y,num;
cin>>N;
memset(Map,0,sizeof(Map));
memset(dp,0,sizeof(dp));
while(cin>>x>>y>>num,x!=0&&y!=0&&num!=0)
{Map[x][y]=num;}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
for(int k=1;k<=N;k++)
{
for(int l=1;l<=N;l++)
{
dp[i][j][k][l]=max(
max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),
max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))
+Map[i][j]+Map[k][l];
if(i==k&&j==l) dp[i][j][k][l]-=Map[i][j];
}
}
}
}
cout<<dp[N][N][N][N];
}
空间复杂度还可以优化。洛谷是真的强,题解很全,错误样例也可以下载(๑╹◡╹)ノ"""