P1004 [NOIP2000 提高组] 方格取数
题目描述
设有$N\times N$的方格图 $(n\leqslant 9)$,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 $0$。如下图所示(见样例):
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
某人从图的左上角的$A$点出发,可以向下行走,也可以向右走,直到到达右下角的 $B$ 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 $0$)。
此人从 $A$ 点到 $B$ 点共走两次,试找出 $2$ 条这样的路径,使得取得的数之和为最大。
输入格式
输入的第一行为一个整数 $N$(表示 $N\times N$ 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的$0$ 表示输入结束。
输出格式
只需输出一个整数,表示$2$条路径上取得的最大的和。
样例数据
输入
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
分析
四维$Dp$,前两维表示第一条路取得的最大值,后两维表示第二条路的最大值,注意判重并删除或如果不重就相加。状态转移方程$$Temp_1=max\{Dp_{i-1,j,p-1,q},Dp_{i-1,j,p,q-1}\}\\Temp_2=max\{Dp_{i,j-1,p-1,q},Dp_{i,j-1,p,q-1}\}\\Dp_{i,j,p,q}=max\{Temp_1,Temp_2\}+G_{i,j}$$
代码
#include <bits/stdc++.h> #define Enter puts("") #define Space putchar(' ') using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } int Dp[101][101][11][11]; int G[101][101]; int x , y , n; int Value; int main() { scanf("%d%d%d%d" , &n ,&x , &y , &Value); while(x && y && Value) G[x][y] = Value , scanf("%d%d" , &x , &y , &Value); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) for(int p = 1; p <= n; p++) for(int q = 1; q <= n; q++) { int Temp1 = max(Dp[i - 1][j][p - 1][q] , Dp[i - 1][j][p][q - 1]); int Temp2 = max(Dp[i][j - 1][p - 1][q] , Dp[i][j - 1][p][q - 1]); Dp[i][j][p][q] = max(Temp1 , Temp2) + G[i][j]; if(i != p && q != j) Dp[i][j][p][q] += G[p][q]; } printf("%d" , Dp[n][n][n][n]); return 0; }