CODEVS 2853 方格游戏

本文探讨了棋盘DP问题中的优化方法,通过精简状态表示,将原四维DP优化为更高效的方案,解决了数据范围扩大带来的挑战。

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

今天早上去做传说中的棋盘dp三兄弟:方格取数,传纸条,方格游戏。前两个虽说属于不同年份的noip提高组,结果除了读入优化其余全部一样,第三题意变化不大,但数据范围变成了n<=100,再和前两个一样任性地开四维并且用四重for循环就不行了,我们需要优化一下。
我认为dp相对于搜索要快在于它记录了搜索的一些值,不再需要重复求解,而dp相对于记忆化搜索要快在于dp比它多了高效的顺序,从子结构到总结构,保证每个状态只被搜索到一次,就像欧拉筛法优于E氏筛法一样,欧拉筛法保证了每个数是奇数还是偶数只被它的最小质因数求出,这就从O(nloglogn)优化到了O(n)。那么我们想要优化dp我们就要从状态入手,状态表达地越简练就越快。四维的做法里我们把目标状态表示为两条路的终点都到了右下角,实际上我们抓住它的特点在走到右下角时两条路都走了2*n-2步,那么我们瞎想一下,如果记录的状态是这两条路走了相同步数的状态呢,我们怎么明确一下状态是什么呢,这时候我们继续瞎想,目标状态还有相同行数,如果再加一维记录这两条路终点相等的行数呢,如果这样的话,这两条路就只能向着相同的方向扩展了,只能一起向右或者一起向下,不然行数就不保证一样了,也就是说一维相同步数,另一维相同行数是不行的,不能再来一维记录相同列数,因为行数列数都相同时就只有一条路了,对于这题来说会导致结果为0,那么我们回到瞎想那里,既然相同行数不可以,那么我们试一下不同行数,看看能不能表示出来明确的状态,事实证明是可以的,这两条路的终点坐标都可以根据步数和行数来求出,那么状态确定了我们要想一下这样是否具有子结构,状态如何转移,转移顺序等,写出状态转移方程,最终打出程序。
以上是我在刷了几天的dp之后的一些想法,如果有什么错误可以偷偷告诉我。。。

#include<cstdio>
#include<iostream>
using namespace std;
int g[110][110],dp[210][110][110]; //第一维是步数,后两维是两条路终点的行数
int max(int a,int b)
{
    return (a>b)?a:b;
}
int abs(int a)
{
    return (a<0)?-a:a;
}
int main()
{
    int n;
    cin>>n;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            cin>>g[i][j];
    for (int k=1;k<=2*n-2;k++)
        for (int i=1;i<=n&&i<=k+1;i++)
            for (int j=1;j<=n&&j<=k+1;j++)
                dp[k][i][j]=max(dp[k][i][j],max(max(dp[k-1][i][j],dp[k-1][i][j-1]),max(dp[k-1][i-1][j],dp[k-1][i-1][j-1]))+abs(g[i][k-i+2]-g[j][k-j+2])); //在能到达当前状态的四个状态里(两条路分别(向右,向右)(向右,向下)(向下,向右)(向下,向下))找最大值后加上当前位置的值。
    cout<<dp[2*n-2][n][n];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值