题目描述
设有 N \times NN×N 的方格图 (N \le 9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 00。如下图所示(见样例):
A
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
B
某人从图的左上角的 AA 点出发,可以向下行走,也可以向右走,直到到达右下角的 BB 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 00)。
此人从 AA 点到 BB 点共走两次,试找出 22 条这样的路径,使得取得的数之和为最大。
输入格式
输入的第一行为一个整数 NN(表示 N \times NN×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 00 表示输入结束。
输出格式
只需输出一个整数,表示 22 条路径上取得的最大的和。
输入输出样例
输入 #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
这道题目,我一开始有一个错误的思路,看了下题解区也有大佬和我一样的做法,因为要找两条路,并且第一条路的点都会变为0,这肯定会影响第二条路的计算,我的错误思路就是,先求一个最大的路作为第一条路,然后再用倒序把这条路上的点都置为0,再求第二大的路作为第二条路。
这种做法WA第三个测试点
很明显这个办法不行,第一条路的选取没有和第二条路的选取同时进行,最终的总和也是会出问题的
先上错误代码
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
const int N=100;
int dirx[2]={1,0};
int diry[2]={0,1};
int mapv[N][N];
int dp[N][N];
int n;
int res;
int fdp()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i][j-1]+mapv[i][j],dp[i-1][j]+mapv[i][j]);
//cout<<"mapv cunzai i is "<<i<<" j is "<<j<<endl;
//cout<<"dp[i][j] is "<<dp[i][j]<<endl;
}
int res1=dp[n][n]; //第一个答案
//cout<<res1<<endl;
int res=res1;
while(res)
{
for(int i=n;i>=1;i--)
{
for(int j=n;j>=1;j--)
{
if(dp[i][j]==res)
{
res=res-mapv[i][j];
mapv[i][j]=0;
}
}
}
}
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i][j-1]+mapv[i][j],dp[i-1][j]+mapv[i][j]);
}
int res2=dp[n][n];
return res2+res1;
}
int main()
{
cin>>n;
while(1)
{
int pos1,pos2,d;
cin>>pos1>>pos2>>d;
if(pos1==0&&d==0&&pos2==0)
break;
mapv[pos1][pos2]=d;
}
cout<<fdp()<<endl;
}
下面就是正确代码啦,有参考洛谷题解大佬的,第一次接触四维数组
//之前的做法是分开两种情况再进行相加,我觉得不可取
//DP是两种情况同时在进行的
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100;
int dp[N][N][N][N];
int mapv[N][N];
int n,pos1,pos2,d;
int MAX(int a,int b,int c,int d)
{
int m;
m=a>b?a:b;
m=m>c?m:c;
m=m>d?m:d;
return m;
}
int main()
{
cin>>n;
while(1)
{
cin>>pos1>>pos2>>d;
if(pos1==0&&pos2==0&&d==0)
break;
mapv[pos1][pos2]=d;
}
//遍历到每种ijxy组合只会有一次,不像深搜和广搜有重复遍历的可能
// 四个n的情况[n][n][n][n]只会遍历一次
//这就不需要考虑把mapv[][]变为0
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
{
dp[i][j][x][y]=MAX(dp[i-1][j][x-1][y],dp[i-1][j][x][y-1],dp[i][j-1][x-1][y],dp[i][j-1][x][y-1])+mapv[i][j]+mapv[x][y];
if(i==x&&j==y)
{
dp[i][j][x][y]-=mapv[i][j]; //多加了一个
}
}
cout<<dp[n][n][n][n]<<endl;
}