首页 > 其他分享 >线性DP-方格取数与传纸条

线性DP-方格取数与传纸条

时间:2024-07-25 16:11:47浏览次数:13  
标签:DP int max 行动 取数 方格 第二次 dp

方格取数

题目链接:方格取数

题解:一种容易想到的思路是:采用贪心法对第一次和第二次行走分别做DP,将两次DP的最优解累加即为答案。

但是这种贪心是错误的,因为两次DP均为对局部求最优解(第二次DP是在第一次DP的影响下求出的局部最优解),这两次DP的结果之和不为全局最优解(不满足无后效性),例如:

0 1 0
2 2 2
1 0 0

对于该方格图,按照上述贪心法,第一次DP会选取第二行的3个2,第二次DP只能选取第一行与第三行的其中一个1,但显然最优解为全取,因此无法用贪心解决本题。

上述讨论引导我们对两次行走通过一次DP解决,即让两次行走同时进行,因此设 \(dp[i][j][x][y]\) 为当前第一次行动的下标为 \((i,j)\),第二次行动的下标为 \((x,y)\) 时,数的最大值。显然 \(i\) 与 \(j\) ,\(x\) 与 \(y\) 之间存在约束关系,即 \(i+j=x+y=k\),因此有 \(j=k-i,y=k-x\),则 \(dp[i][j][x][y]\) 等价于 \(dp[i][k-i][x][k-x]\)。

发现第二维与第四维只需要通过 \(k\) 进行维护即可,因此状态表示设为 \(dp[k][i][x]\),表示当前行动下标和为 \(k\) 时,第一次行动横坐标为 \(i\),第二次行动横坐标为 \(x\) 时的取数最大值。

对于状态转移,需要考虑四种情况:

  • 第一次行动从上方转移过来,第二次行动从上方转移过来,对应状态 \(dp[k-1][i][x]\) (横坐标不变)
  • 第一次行动从左方转移过来,第二次行动从上方转移过来,对应状态 \(dp[k-1][i-1][x]\)
  • 第一次行动从上方转移过来,第二次行动从左方转移过来,对应状态 \(dp[k-1][i][x-1]\)
  • 第一次行动从左方转移过来,第二次行动从左方转移过来,对应状态 \(dp[k-1][i-1][x-1]\)

得到所有状态后,转移时只需要加上两个坐标对应的值即可,这里需要注意有可能两次行动移动到同一位置,这个时候只需要加一次值,需要特别判断一下。最后将上述所有状态取最大值即可。

除此之外 由于 \(k\) 的取值为 \(2-2n\) 因此通过 \(k\) 求下标时需要判断是否在方格图内。

AC代码:

#include<iostream>
#include<algorithm>

using namespace std;
const int N = 15;
int a[N][N];
int dp[N * 2][N][N];
int n;

void solve() {
    cin >> n;
    while(1) {
        int x, y, c;
        cin >> x >> y >> c;
        if(x == 0 && y == 0 && c == 0)    break;
        a[x][y] += c;
    }
    
    for (int k = 2; k <= n * 2; k ++) {
        for (int i = 1; i <= n; i ++) {
            for (int x = 1; x <= n; x ++) {
                int j = k - i, y = k - x;
                int t = a[i][j];
                if (i != x)    t += a[x][y];
                if (j < 1 || j > n || y < 1 || y > n)    continue;
                int w1 = dp[k - 1][i][x] + t;
                int w2 = dp[k - 1][i - 1][x] + t;
                int w3 = dp[k - 1][i][x - 1] + t;
                int w4 = dp[k - 1][i - 1][x - 1] + t;
                dp[k][i][x] = max(dp[k][i][x], max(w1, max(w2, (max(w3, w4)))));
            }
        }
    }
    
    cout << dp[2 * n][n][n] << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    solve();
}

传纸条

题目链接:传纸条

题解:这道题与上一道题的区别在于,该题要求第二条路径不能选择第一条路径选过的位置,即两条路径不能存在交点,而上一道题允许两条路径交叉。

然而上一道题的最优解的路径一定不存在交叉的情况,因此这两道题本质相同,下面给出证明。

证明:假设最优解的路径存在交叉,由于第一条路径走过之后使得该位置的权值变为 \(0\),因此若第二条路径与第一条路径存在交叉,则交叉点在第二次经过时贡献的值为 \(0\),而第二次不经过该位置而从其他位置到达该位置的下一个点,其贡献值一定大于等于 \(0\),答案不会变得更差,因此最优解不存在相交情况。

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 55;
int a[N][N];
int dp[N * 2][N][N];
int n, m;

void solve() {
    cin >> m >> n;
    for (int i = 1; i <= m; i ++) {
        for (int j = 1; j <= n; j ++) {
            cin >> a[i][j];
        }
    }
    
    for (int k = 2; k <= m + n; k ++) {
        for (int i = 1; i <= m; i ++) {
            for (int x = 1; x <= m; x ++) {
                int j = k - i, y = k - x;
                if (j < 1 || j > n || y < 1 || y > n)    continue;
                int t = a[i][j];
                if (i != x)    t += a[x][y];
                int w1 = dp[k - 1][i][x] + t;
                int w2 = dp[k - 1][i - 1][x] + t;
                int w3 = dp[k - 1][i][x - 1] + t;
                int w4 = dp[k - 1][i - 1][x - 1] + t;
                dp[k][i][x] = max(dp[k][i][x], max(w1, max(w2, max(w3, w4))));
            }
        }
    }
    
    cout << dp[m + n][m][m];
    
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    solve();
}

标签:DP,int,max,行动,取数,方格,第二次,dp
From: https://www.cnblogs.com/Ray0430/p/18323392

相关文章

  • DFS和DP--过河卒
    题目描述:棋盘上 A 点有一个过河卒,需要走到目标 ......
  • python中scrapy爬取数据get()与getall()区别
    在使用scrapy进行爬取数据的时候,有些时候需要爬取的是一段文本,或者一个div里面有很多内容,这时候我们就要使用到get()或者getall()来获取数据: get():是获取的满足条件的第一个数据。getall():是获取的满足条件的所有数据。scrapyget()getall()原理在Scrapy中,get(......
  • .NET TCP、UDP、Socket、WebSocket
    做.NET应用开发肯定会用到网络通信,而进程间通信是客户端开发使用频率较高的场景。进程间通信方式主要有命名管道、消息队列、共享内存、Socket通信,个人使用最多的是Sokcet相关。而Socket也有很多使用方式,Socket、WebSocket、TcpClient、UdpClient,是不是很多?HttpClient与TcpClien......
  • 高 DPI 下的 PyPlot 绘图更大,但仍然模糊
    我正在按照教程生成点的散点图,按簇着色,并根据每个点在其各自簇中的成员资格强度进行颜色饱和。我提到了着色细节,以防它们影响分辨率,但我怀疑它们不会。我发现,如果我增加PyPlot图形的DPI,图形的大小会增加,但仍然非常模糊。下面是我的测试代码,它生成一个小DPI数字和一......
  • 从雪花获取数据
    因此,我一直在尝试设置一个流程,以使用SnowflakePython连接器从python中的Snowflake数据库中提取数据。我已经制作了一个请求数据的方法(如下所示)importsnowflake.connectordefrequest_data(s,query):snowflake_connection=snowflake.connector.connect(user=......
  • 树形 dp 学习笔记
    状态设计基本上每一种dp都有一种标准的dp定义方式,树形dp也是如此:定义\(f[u]\)表示以\(u\)为根节点的子树里最优的决策。从分析子树入手,转移便是找到某一子树中,根节点与各子树、边权间的递推关系。最优解常常是关于根节点的函数。它的子结构是一颗子树。实现方式......
  • 状态压缩 dp
    \(\texttt{0x00}\):概念状压DP是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。$\text{----OIWiki}$简单说来,就是我们通过普通的状态表示无法直接推出状态转移方程了,这时候将当前状态拓展的“轮廓”作为状态表示的一维,而考虑到空间复杂度和计算机原理,主要使用二......
  • Wordpress安装到win10(2024年7月)
    目录1.wordpress介绍2下载应用2.1.wordpress2.2XAMPP 2.3PHPmyadmin3.配置应用3.1XAMPP进程3.2文件配置3.3phpmyadmin配置4.配置网页4.1数据库创建 4.2安装wordpress5.进入面板6.总结1.wordpress介绍WordPress是一个开源内容管理系统(CMS),它允许用户构......
  • 解决wordpress媒体上传一张图片裁剪成多张的问题
    问题在使用wordpress的媒体库的过程中我发现,我上传一张图片,但是在服务器的文件中会自动裁剪处多张不同尺寸的图片,这样在不需要的情况下,会造成存储压力解决1.wordpress后台设置打开wordpress的后台设置→媒体把这里的勾选去掉然后保存更改2.代码内修改代码文件路径/wp-con......
  • 51nod-3983走方格
    https://class.51nod.com/Html/Textbook/Problem.html#problemId=3983&textbookChapterId=724https://class.51nod.com/Html/Textbook/ChapterIndex.html#textbookId=126&chapterId=337移动与时间段有关,如果按照时间段划分状态那么每一段内只有一条线性的转移。需要一行一行或......