P2380 狗哥采矿【普及+提高】棋盘DP

狗哥采矿 - 洛谷

所谓棋盘dp就是dp[i][j]代表了(1,1)到(i,j)范围内的收益,在矩阵前缀时,利用了一些容斥原理达到状态转移的目的。本题为了维护矩阵形状,考虑到每个点其实只能一直向上或者一直向下,只需要dp[i-1][j]加上左边前缀和与dp[i][j-1]加上上部前缀和即可。

唯一让我疑惑的是,本次i,j的连接方式和其内部的1连接方式根本不同时,为什么不会产生影响呢?

宏观来说,我们向左插入直线时,选择的是上部的矩形,我们向上插入时,选择的是左部的,直线与被选择的矩形根本不想交,所以直线与矩形根本不会互相影响。而我们dp[i-1][j]与d[i][j-1]的状态内部已经安排好了没有冲突的最优情况。我们此时加入一条左或上的边,也是合理的,那么dp[i][j]就合理了,其他更大的矩形就可以利用这一合理性,构建更大的合理。

微观来说,见图。

 首先看边界,最上面一定全部向左时,dp[1][j]才能最大值,最左侧全部向上时dp[i][1]才能取最大值。由于(1,1)左右答案都相同,所以这还不能充分说明问题。

 到达(1,2)时,两种扩展方式,向上时,dp[i][j-1]内部不会影响本次操作。但本次方向显然和上方(1,2)位置方向发生冲突,但暂时还没有影响后续结果,我们继续推,假设本次是向上推最优。

 (2,3)位置,向右推时,dp[2][2]并不会影响本次操作,而且我们这样也把(1,3)改成了向上,不会存在断层情况。那如果本次向左扩展最优呢,那么我们又得把左边全部染成黄色,dp[1][3]派上了用场,dp[1][3]在到达(2,2)点时被“修改”了部分方向,可我们调用时,它仍然保持这它内部最优的情况,而这种情况是连续无断层的。

#include <iostream>
# include<algorithm>
# include<cstring>

using namespace std;
typedef long long int ll;

int dp[550][550];
int bei[550][550];
int xi[550][550];
int main()
{
    int n,m;
    while(cin>>n>>m&&n&&m)
    {



    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
           int x;
           cin>>x;

          xi[i][j]=xi[i][j-1]+x;

        }
    }


    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int x;
            cin>>x;


          bei[i][j]=bei[i-1][j]+x;

        }
    }



    memset(dp,0,sizeof(dp));


    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            dp[i][j]=max(dp[i-1][j]+xi[i][j],dp[i][j-1]+bei[i][j]);
        }
    }

    cout<<dp[n][m]<<'\n';

    }


    return 0;
}

以此类推,发现即使出现了内部冲突的情况,也不会对本次造成任何影响。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦三码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值