[wikioi]传纸条

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; 

}

  

你可能感兴趣的:(IO)