洛谷P1006 传纸条 (DP)

本文探讨了一种利用双线程动态规划(DP)解决特定问题的方法。通过定义状态dp[x1][y1][x2][y2]来表示两个角色A和B分别到达不同位置的最大收益,并详细阐述了状态转移的过程,避免了坐标相同的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意分析

一开始想的是进行两遍DP,这样明显是错误的,因为会有重复走的位置,这是不符合题意的。
然后看题解,很多写的是双线程DP,我不太感觉的出来。其实想一下,因为有两个人要描述这两个人的状态,那肯定是分别用他们在平面的坐标,这是最直接的。
dp[x1][y1][x2][y2]dp[x1][y1][x2][y2] 表示A走到(x1,y1)(x1,y1), B走到(x2,y2)(x2,y2) 时最大的值。
有了状态定义,然后就可以考虑状态的转移了。

题目要求是传过来传回去,其实这样是和同时从起点到终点,选择两条不同的路径是等价的。
只能向右和向下走,所以 =max(AB)+A+B当前状态=max(所有转移到AB所在点的可能)+A所在点的值+B所在点的值
如果这么写肯定错了,因为还要注意AB的坐标不能相同,也就是AB不应该从除终点外的一个点开始转移,不能转移到除起点外的同一个点。

注意了这点,大胆的写记忆花搜索,或者DP都是可以的。

代码总览

#include<bits/stdc++.h>
using namespace std;
const int nmax = 60;
int mp[nmax][nmax];
int dp[nmax][nmax][nmax][nmax];
int n,m;
int nx[2] = {0,1};
int ny[2] = {1,0};
bool leagal(int x1, int y1, int x2, int y2){
    if(x1 < 1 || x1 > n || y1 < 1 || y1 > m) return false;
    if(x2 < 1 || x2 > n || y2 < 1 || y2 > m) return false;
    if(x1 == x2 && y2 == y1 && (x1 != n || y1 != m)) return false;
    return true;
}
int getdp(int x1, int y1, int x2, int y2){
    if(dp[x1][y1][x2][y2]) return dp[x1][y1][x2][y2];
    for(int i = 0;i<2;++i){
        int xx1 = x1 + nx[i];
        int yy1 = y1 + ny[i];
        for(int j = 0;j<2;++j){
            int xx2 = x2 + nx[j];
            int yy2 = y2 + ny[j];
            if(leagal(xx1,yy1,xx2,yy2)){
                dp[x1][y1][x2][y2] = max(dp[x1][y1][x2][y2], getdp(xx1,yy1,xx2,yy2) + mp[x1][y1] + mp[x2][y2]);
            }
        }
    }
    return dp[x1][y1][x2][y2];
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i = 1;i<=n;++i){
        for(int j = 1;j<=m;++j){
            scanf("%d",&mp[i][j]);
        }
    }
    printf("%d\n",getdp(1,1,1,1));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值