http://wikioi.com/problem/1169/
棋盘型的动态规划,这道题可以看成是从左上角向右下角走两条不重合的路(除了开始和结尾)。动态规划要想的是状态和阶段,状态是(x1,y1,x2,y2),两个分别一步一步走,所以阶段就是L=x+y。这样状态也能简化成三维(L, x1, x2)。约束是其中每一部两个棋子不能重合(如果重合就设为0)。状态转移是每一步都可以从之前的四个状态走过来,比较取最大值就行。
如果用循环的方式写,则L从小到大,x1,x2也从小到大循环。这里用了备忘录方式写,就比较方便。
#include <cstdio> #include <iostream> #include <memory.h> using namespace std; const int MAX_N = 51; int M,N; int G[MAX_N][MAX_N]; int f[MAX_N*2][MAX_N][MAX_N]; // L, X1, X2 void init() { int i,j; scanf("%d %d",&M,&N); for (i=1;i<=M;i++) for (j=1;j<=N;j++) scanf("%d",&G[i][j]); memset(f,-1,sizeof(f)); } bool isValid(int a,int b,int c,int d) { if (a>M||c>M) return false; if (b>N||d>N) return false; if (a<1||c<1) return false; if (b<1||d<1) return false; return true; } int process(int L,int x1,int x2) { if (L==2) return 0; int y1 = L-x1; int y2 = L-x2; if (!isValid(x1,y1,x2,y2)) return 0; if (x1==x2&&y1>=y2&&!(x1==M&&y1==N)) return 0; if (f[L][x1][x2]!=-1) return f[L][x1][x2]; int tmp=0; tmp=max(tmp,process(L-1,x1,x2)); tmp=max(tmp,process(L-1,x1,x2-1)); tmp=max(tmp,process(L-1,x1-1,x2)); tmp=max(tmp,process(L-1,x1-1,x2-1)); return f[L][x1][x2]=tmp+G[x1][y1]+G[x2][y2]; } int main() { init(); printf("%d",process(M+N,M,M)); return 0; }