[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; 
}

  

原文地址:https://www.cnblogs.com/lautsie/p/3347804.html