RQNOJ 传纸条

点击打开链接

思路: dp
分析:
1 题目要求找到两条不同的路线使得和最大,那么我们可以换种思路就是看成是都是从(1,1)这个点出发的两条路线并且不相交,最后到达(n , m)这个点的和最大
2 题目说了从左上角往右下角传递的时候只能向下或向右,从右下角往左上角传递的时候只能向左或向上,那么很明显到达终点只要n+m步
3 那么由于是同时出发并且两个路线是不相交,那么在第k步的时候我们就可以知道两个路线的点肯定在同一条对角线上,一个n+m的矩形有n+m条对角线那么刚好符合起点到达终点需要n+m步
4 那么现在最难的就是去推出一个无后效性并且唯一表示一个状态的式子,经过研究可以得到dp[k][i][j]表示第k步的时候第一条路线在i列,第二条路线在j列。由于通过k 和 列数 我们也可以知道行数,所以我们可以得到以下的状态转移方程 dp[k][i][j] = max{dp[k-1][i][j] , dp[k-1][i-1][j] , dp[k-1][i-1][j-1] , dp[k-1][i][j-1]} + num[x][i]+num[y][j] (x,y表示的是行数)

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 110;

int n , m , num[MAXN][MAXN];
int dp[MAXN][MAXN][MAXN];

int solve(){
    memset(dp , 0 , sizeof(dp));
    for(int k = 2 ; k <= n+m ; k++){
        for(int i = 1 ; i <= m ; i++){
            for(int j = 1 ; j <= m ; j++){
                if(i != j){
                    int tmp = max(dp[k-1][i][j] , dp[k-1][i][j-1]); 
                    tmp = max(tmp , dp[k-1][i-1][j-1]); 
                    tmp = max(tmp , dp[k-1][i-1][j]); 
                    dp[k][i][j] = tmp+num[k+1-i][i]+num[k+1-j][j];
                }
            }
        }
    }
    return max(dp[n+m-1][m-1][m] , dp[n+m-1][m][m-1]);
}

int main(){
    while(scanf("%d%d" , &n , &m) != EOF){
        for(int i = 1 ; i <= n ; i++) 
            for(int j = 1 ; j <= m ; j++)
                scanf("%d" , &num[i][j]);
        printf("%d\n" , solve());
    } 
    return 0;
}



你可能感兴趣的:(OJ)