hiho 1617 - 方格取数 - dp

题目链接

描述

给定一个NxN的方格矩阵,每个格子中都有一个整数Aij。小Hi和小Ho各自选择一条从左上角格子到右下角格子的路径,要求路径中每一步只能向右或向下移动,并且两条路径不能相交(除了左上右下起止方格)。  

现在将两条路径经过的整数加起来求和。你能计算出这个和最大是多少吗?

输入

第一行包含一个整数N。  

以下N行每行包含N个整数,代表方格矩阵中的数字。  

对于50%的数据,1 ≤ N ≤ 50  

对于100%的数据,1 ≤ N ≤ 200 1 ≤ Aij ≤ 100

---------------------------------------------------------------------------------------------------------------------------------------------

如下图那样一行行的处理

dp[row][i][j]代表 第row行选取第i和第j个元素时的最大值,

dp[row][i][j]最多只和上一行的四个元素相关,注意上三角和下三角这四个元素的索引方式不同。

因为第row行只和第row-1行相关,所以只需保存前一行的结果。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 256;
int dp[N][N][2];
int A[N][N];
int n;
int get(int row,int i){
    if(row<=n+1){
        if(i>=row) return 0;
        return A[row-i][i];
    }
    else{
        int x = row-n-1+i;
        if(x>n) return 0;
        return A[row-x][x];
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&A[i][j]);
    memset(dp,0,sizeof(dp));
    dp[1][1][0] = A[1][1]*2;
    int cur = 1;
    for(int row=3;row<n*2;row++){
        int cnt = (row>n+1)?(n*2-row+1+1):(row);
        int gap = (row>n+1)? 1: -1;
        for(int i=1;i<cnt;i++) for(int j=i+1;j<cnt;j++){
             int max1 = std::max(dp[i][j][!cur],dp[i+gap][j][!cur]);
             int max2 = std::max(dp[i][j+gap][!cur],dp[i+gap][j+gap][!cur]);
             dp[i][j][cur] = std::max(max1,max2)+get(row,i)+get(row,j);
        }
        cur = cur?0:1;
    }
    printf("%d\n",dp[1][2][!cur]+A[n][n]*2);
    return 0;
}

 

posted @ 2017-10-29 15:12  redips  阅读(293)  评论(0编辑  收藏  举报