传纸条 luoguP1006
题目描述
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排坐成一个 mm 行 nn 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标 (1,1),小轩坐在矩阵的右下角,坐标 (m,n)(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用 00 表示),可以用一个 [0,100][0,100] 内的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度之和最大。现在,请你帮助小渊和小轩找到这样的两条路径。
输入格式
第一行有两个用空格隔开的整数 mm 和 nn,表示班里有 mm 行 nn 列。
接下来的 mm 行是一个 m×nm×n 的矩阵,矩阵中第 ii 行 jj 列的整数表示坐在第 ii 行 jj 列的学生的好心程度。每行的 nn 个整数之间用空格隔开。
输出格式
输出文件共一行一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
题面是直接复制 的,有点炸,但是没关系(反正不会有人到位这里来看题面
我觉得这题的难点在于同时要找到两条路径,并且不能交叉,这个在dp里面是比较难进行限制和定义的
还有就是这种dp类型对我可能是第一次,比较陌生。
这个最简单的状态设计我都是看别人的。。。
设f[i][j][k][l]表示一条路径走到了[i][j],另一条走到了[k][l]时,最大的好感度之和
转移比较明显,就从前面的点转移过来就好了,但是转移的时候要保证不会走到两个重合的点,这样就保证了两个路径不相交。
时间复杂的O(n^4),n最大50,可以接受。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
char c=getchar();int a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int f[51][51][51][51],n,m,a[51][51];
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]=read();
}
}
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<=n;k++)
{
for(int h=0;h<=m;h++)
{
if(i==0||j==0||k==0||h==0)
f[i][j][k][h]=-1145141919;
else
f[i][j][k][h]=0;
}
}
}
}
f[1][1][1][1]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=n;k++)
{
for(int h=1;h<=m;h++)
{
if((i==k&&j==h))
continue;
f[i][j][k][h]=max(f[i][j][k][h],f[i-1][j][k-1][h]+a[i][j]+a[k][h]);
f[i][j][k][h]=max(f[i][j][k][h],f[i-1][j][k][h-1]+a[i][j]+a[k][h]);
f[i][j][k][h]=max(f[i][j][k][h],f[i][j-1][k-1][h]+a[i][j]+a[k][h]);
f[i][j][k][h]=max(f[i][j][k][h],f[i][j-1][k][h-1]+a[i][j]+a[k][h]);
}
}
}
}
cout<<max(f[n-1][m][n-1][m],max(f[n-1][m][n][m-1],max(f[n][m-1][n-1][m],f[n][m-1][n][m-1])))<<endl;
return 0;
}
很奇怪,如果我尝试把结果直接转移到f[n][m][n][m]上然后输出,就会错,目前认为是我上面转移边界判断写错了
懒得找了
可以发现,其实这个4维数组里面是大部分用不上的,意思就是,我们浪费了非常多的空间和时间复杂度给了不可能的情况,因为我们每一次都是两边走一步
所以很容易可以发现,类似f[1][1][n][m]这样的状态是不可能也不存在也无意义的,但是它们的存在占用了大量转移的时间和空间
可以考虑优化考虑这一类无意义转移的特征
我们的转移都是一次性走两步的,很明显,这样的情况才是我们真正要的。
我们一次走一步,其实走的总步数就是曼哈顿距离,很明显,两条路的走的步数是一样的。
所以当两边同时走的时候,需要我们转移的地方很明显是没有那么多的,只有步数一样的两个点的状态,我们的转移才是有意义的,否则这个计算其实是没有任何作用的。
所以,我们可以增加一个状态,步数i,另外两个状态就是两个路径的竖直位置。
因为我们每次总是向下和向右走,所以通过步数和竖直位置可以直接计算出来它的水平距离。
这样那些多余的计算和空间就被优化掉了。
代码我懒得写了,主要是这个思考的方法
首先,这个优化依旧是从这个问题的特质出发的,我们发现了两边的步数i是一样的
(应该是我一开始就看的是别人的题解的原因,我感觉如果让我来设计状态,我不会这么暴力)
所以没有其次了(因为我感觉没必要)
然后就是这个问题的一个转化
我们把回传的问题转化为了从上往下的第二条路径。
这个是十分重要的,如果是先找到第一条,再去找第二条,时间复杂度会直接爆炸,而且不可做。
所以这个特性其实非常重要和有用的,因为正着麻烦,那就反着来,正难则反
而且利用这个,其实也是把不可相交这个要求的处理给简化, 一举两得,十分巧妙。。。
这应该就算是一道好题吧,比较的灵活
如果我比赛的时候遇到这个,我肯定是写不出来的
要怎么才能写出来呢?
1.发现这个特征,就是从下往上和从上往下是没有区别的
2.转化问题,把问题转化为找两个一起往下的路径(这个我想不到)
后面就比较简单了,我觉得这种转化其实也是dp的一个难点
只能靠积累了吧。。。
多积累,应该会在一定程度质变的。
加油
传纸条 luoguP1006的更多相关文章
- luoguP1006 传纸条
题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个 m" role="presentation& ...
- tyvj1011 传纸条
背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端, ...
- NOIP2008 传纸条
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...
- NOIP2008传纸条[DP]
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...
- NOIP2008 T3 传纸条 解题报告——S.B.S.
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...
- [NOIP2008] 提高组 洛谷P1006 传纸条
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...
- TYVJ 1011 NOIP 2008&&NOIP 2000 传纸条&&方格取数 Label:多线程dp
做题记录:2016-08-15 15:47:07 背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行 ...
- nyoj 61 传纸条
点击打开链接 传纸条(一) 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做 ...
- P1011 传纸条//dp优化改进状态表示
P1011 传纸条 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不 ...
- Wikioi 1169 传纸条
这道题是我人生第一道双线动规题,因此我觉得还是很有必要记录下来. 刚接触到这道题的时候我第一反应是单线的动规,可是下一秒我就觉得这样做可能会有问题,因为从左上角(以下简称A)到右下角(以下简称B)通过 ...
随机推荐
- 图书商城Vue+Element+Node项目练习(...)
本系列文章是为学习Vue的项目练习笔记,尽量详细记录一下一个完整项目的开发过程.面向初学者,本人也是初学者,搬砖技术还不成熟.项目在技术上前端为主,包含一些后端代码,从基础的数据库(Sqlite).到 ...
- MYSQL之批量删除(mybatis)
如果参数是array数组 <update id="deleteAll"> delete from C_V WHERE UUID in <foreach item= ...
- 【Python】Locust持续优化:InfluxDB与Grafana实现数据持久化与可视化分析
前言 在进行性能测试时,我们需要对测试结果进行监控和分析,以便于及时发现问题并进行优化. Locust在内存中维护了一个时间序列数据结构,用于存储每个事件的统计信息. 这个数据结构允许我们在Chart ...
- centos系统给centos-root硬盘扩容
此服务器为虚拟机,通过lsblk命令查看当前虚拟机硬盘: 其中一块硬盘大小为100G,已作为系统盘使用,但是只分配了15G的空间使用,需要对剩余空间进行分区,并扩容到对应centos卷组的root目录 ...
- .NET Core 3.1使用docker打包并部署
目录 简介 环境介绍 开发环境 部署环境 编写Dockerfile文件 生成Docker镜像 运行容器 访问接口 结语 简介 本文主要说明使用.NET Core 3.1搭建的站点如何使用docker打 ...
- Spring—bean的作用域
beans的作用域 单例模式(Spring默认模式) <?xml version="1.0" encoding="UTF-8"?> <bean ...
- C# CEFSharp WCF开发桌面程序实现“同一网站多开”
前言 孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说:"对呀,对呀!CEFSharp,你用过么?访问同一网址实现多开怎么实现?比如我有3个淘宝店,我想同时登录维护,就像传说中的指 ...
- 采用PCA算法&KMeans算法来实现用户对物品类别的喜好细分(菜篮子分析)(附带数据集下载)
实现该项目的流程如下 """ 项目:用户对物品类别的喜好细分(菜篮子分析) 主算法:PCA降维算法 KMeans算法 总思路 1.导包 2.获取数据 3.数据处理 5.特 ...
- 自定义javascript中call、bind、apply方法
call.bind.apply都是Function原型上的方法,用于改变this的指向 自定义函数 js中的call.bind.apply是用c++代码实现的,我们这里使用js代码做一个模式,没有把所 ...
- asp.net core之EfCore
EF Core(Entity Framework Core)是一个轻量级.跨平台的对象关系映射(ORM)框架,用于在.NET应用程序中访问和操作数据库.它是Entity Framework的下一代版本 ...