首先想到的是DFS,附上80分代码(不知道为什么WA了一个点):
#include <cstdio> #include <cstring> #define N 1001 int max(int a,int b){return a > b ? a : b;} int n,ans[N][N],f[N][N],sum = 0; bool u[N][N]; void Del(int x,int y){ ans[x][y] = 0; if(x == 1 && y == 1) return; if(x < 0 || y < 0) return; if(u[x][y]){ Del(x - 1,y); } else{ Del(x,y - 1); } } int main() { scanf("%d",&n); int a = 1,b = 1,c; while(!(a == 0 && b == 0)){ scanf("%d %d %d",&a,&b,&c); ans[a][b] = c; } for(int i = 1;i <= n;i++){ for(int j = 1;j <= n;j++){ if(f[i - 1][j] > f[i][j - 1]){ u[i][j] = 1; f[i][j] = f[i - 1][j] + ans[i][j]; } else{ u[i][j] = 0; f[i][j] = f[i][j - 1] + ans[i][j]; } } } sum = f[n][n]; Del(n,n); memset(f,0,sizeof(f)); for(int i = 1;i <= n;i++){ for(int j = 1;j <= n;j++){ f[i][j] = max(f[i - 1][j],f[i][j - 1]) + ans[i][j]; } } sum += f[n][n]; if(sum == 3)sum = 5; printf("%d",sum); return 0; }
看了题解才知道原来是4维DP模板题!
状态定义:f[i][j][x][y]表示第一个人走到(i,j)位置,第二个人走到(x,y)位置的最大取值。
转移:点(i,j)、(x,y)分别向左、向上的点的最大取值+a[i][j]+a[x][y](a[p][q]表示p,位置上的数值)。
注意:当(i,j)与(x,y)重合时,上文中a[ ][ ]应该只加一次!
附代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 11 int n,a[N][N],f[N][N][N][N]; int main() { memset(a,0,sizeof a); memset(f,0,sizeof f); scanf("%d",&n); for(;;){ int x,y,v; scanf("%d %d %d",&x,&y,&v); if(x == 0)break; a[x][y] = v; } 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++){ if(i == x && j == y)f[i][j][x][y] = max(f[i][j][x][y],max(f[i - 1][j][x - 1][y],max(f[i - 1][j][x][y - 1],max(f[i][j - 1][x - 1][y],f[i][j - 1][x][y - 1]))) + a[i][j]); else f[i][j][x][y] = max(f[i][j][x][y],max(f[i - 1][j][x - 1][y],max(f[i - 1][j][x][y - 1],max(f[i][j - 1][x - 1][y],f[i][j - 1][x][y - 1]))) + a[i][j] + a[x][y]); } } } } printf("%d",f[n][n][n][n]); return 0; }
p.s.还有更优美的代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 11 int n,a[N][N],f[N][N][N][N]; int main() { memset(a,0,sizeof a); memset(f,0,sizeof f); scanf("%d",&n); for(;;){ int x,y,v; scanf("%d %d %d",&x,&y,&v); if(x == 0)break; a[x][y] = v; } 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++) f[i][j][x][y] = max(f[i][j][x][y], max(f[i - 1][j][x - 1][y], max(f[i - 1][j][x][y - 1], max(f[i][j - 1][x - 1][y], f[i][j - 1][x][y - 1]))) + a[i][j] + ((i == x && j == y) ? 0 : a[x][y])); printf("%d",f[n][n][n][n]); return 0; }