洛谷P1004 方格取数
一道DP题,虽然数据范围很小,但还是需要多思考思考。作为NOIP 2000 提高组第四题,还是需要构思的。
题目描述
设有N \times NN×N的方格图(N \le 9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字00。如下图所示(见样例):
某人从图的左上角的AA点出发,可以向下行走,也可以向右走,直到到达右下角的BB点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字00)。
此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入输出格式
输入格式:
输入的第一行为一个整数N(表示N \times N×N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的00表示输入结束。
输出格式:
只需输出一个整数,表示22条路径上取得的最大的和。
输入输出样例
输入样例
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
输出样例
67
说明
NOIP 2000 提高组第四题
——摘自洛谷
当我读题第一遍时,我是这样的:
第二次看懂了一些
于是灵光一闪,深搜!
便有了这样一个图:
对,这样把整张图深搜一遍,把数字的和叠加起来,回溯再搜一遍,最后比较大小,那么便AC!可转念一想,一张图有那么条路径,不会TLE吗?
所以,还是用DP吧。
我们假设有两个人,A1和B1。他们分别找:
亦可简化成线:
可以推出方程:
dp[i][j][ii][jj]=max(dp[i-1][j][ii-1][jj],max(dp[i][j-1][ii-1][jj],max(dp[i-1][j][ii][jj-1],dp[i][j-1][ii][jj-1])))+a[i][j]+a[ii][jj];
因为是两个人,所以开四维数组:
int a[100][100];
int dp[25][25][25][25];
代码主体:
while(1){
cin >> x >>y>>z;
if(x==0&&y==0&&z==0)break;
a[x][y]=z;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int ii=1;ii<=n;ii++){
for(int jj=1;jj<=n;jj++){
dp[i][j][ii][jj]=max(dp[i-1][j][ii-1][jj],max(dp[i][j-1][ii-1][jj],max(dp[i-1][j][ii][jj-1],dp[i][j-1][ii][jj-1])))+a[i][j]+a[ii][jj];
}
}
}
}
但写了这么多,我相信你会爆零。机房的WA开了,我带你看看
Why?
很简单,既然是两个人,如果他们走在了一起,不会重复吗?
于是,再加一条判断:
if(i==ii&&j==jj)
dp[i][j][ii][jj]-=a[i][j];
代码总体:
#include<bits/stdc++.h>
using namespace std;
int a[100][100];
int dp[25][25][25][25];
int x,y,z;
int main(){
int n;
cin >> n;
while(1){
cin >> x >>y>>z;
if(x==0&&y==0&&z==0)break;
a[x][y]=z;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int ii=1;ii<=n;ii++){
for(int jj=1;jj<=n;jj++){
dp[i][j][ii][jj]=max(dp[i-1][j][ii-1][jj],max(dp[i][j-1][ii-1][jj],max(dp[i-1][j][ii][jj-1],dp[i][j-1][ii][jj-1])))+a[i][j]+a[ii][jj];
if(i==ii&&j==jj)
dp[i][j][ii][jj]-=a[i][j];
}
}
}
}
cout <<dp[n][n][n][n];
return 0;
}