Codeforces Round #131 (Div. 1) C. Relay Race

C. Relay Race

题目链接

标签:dp

题意:

  • 给出一个边长为n(1 ≤ n ≤ 300)的矩阵,每个方格中有一个数( - 1000 ≤ x ≤ 1000)
  • 小A从(1,1)移动到(n,n),小B从(n,n)移动到(1,1)
  • 上述条件实际上等价于两人从(1,1)移动到(n,n)
  • 求两人移动过程中覆盖方格中的数字的最大总和,两人都经过的方格只能加一次

思路:

由于题目所求是两个人在矩阵中移动的覆盖值最大,我们首先想到的是四维dp,令每个维度分别表示两人的坐标,但是空间不够
矩阵大小为n*n时,从左上角到右下角的步数为2 * (n-1)
观察到步数与横纵坐标的关系,我们尝试将dp优化到三维dp[step][x][i]
step表示两人分别走了step
xi分别表示两人位于第几行
可推 y = step-x+2j = step-i+2 ,即两人的坐标分别为(x,y),(i,j)

转移方程比较简单,看下面注释即可
方格中的数字会出现负数,因此dp数组要初始化一下

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=300+5;
const int mod=1e9+7;
int a[N][N];
int dp[2*N][N][N];//step表示两人分别走了step步  x i分别表示两人位于第几行  

int main() {
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    memset(dp,-0x3f,sizeof(dp));
    dp[0][1][1] = a[1][1];
    for(int step=1;step<=2*(n-1);step++){
        for(int x=1;x<=n;x++){
            for(int i=1;i<=n;i++){
                int j = step-i+2, y = step-x+2;
                if(j<1 || j>n || y<1|| y>n) continue;
                dp[step][x][i] = max(dp[step][x][i],dp[step-1][x-1][i]+a[i][j]+a[x][y]);//A向下走,B向右走
                dp[step][x][i] = max(dp[step][x][i],dp[step-1][x][i-1]+a[i][j]+a[x][y]);//A向右走,B向下走
                dp[step][x][i] = max(dp[step][x][i],dp[step-1][x-1][i-1]+a[i][j]+a[x][y]);//A向下走,B向下走
                dp[step][x][i] = max(dp[step][x][i],dp[step-1][x][i]+a[i][j]+a[x][y]);//A向右走,B向右走
                if(x==i&&y==j) dp[step][x][i] -= a[i][j];//两人位置重复,减去重复计算
            }
        }
    }
    cout<<dp[2*(n-1)][n][n]<<le;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值