这道题是我人生第一道双线动规题,因此我觉得还是很有必要记录下来。

刚接触到这道题的时候我第一反应是单线的动规,可是下一秒我就觉得这样做可能会有问题,因为从左上角(以下简称A)到右下角(以下简称B)通过动规采用了最优线路,从B到A又用动规找出了一条最优线路且不与之前从A到B的线路有交叉,但是这样总权值却未必是最大的。因为DP都中断了,所以无法确保是最大权值,你可以自己列举出例子,这里就不说了。也许有人会想,我不中断不就行了,到达从B到A中途的某个点C时的权值等于未经过C点且能到达C点所有路径中权值最大的那个再加上C点的值。那行,请问代码你要怎么写?想想都觉得麻烦而且无从下手,题做多了你就有种直觉这样不是最直观最简便最具有“答案范”的答案。

接下来我想到的是广搜。找出从A到B点再从B到A点的不重复道路可以看作是从A点出发寻找两条不相交的道路到达B点,至于说从A点到B点时只能往右和往下传纸条,从B点到A点只能往上和往左传纸条无非就是告诉你每个点只可能从两个方向到达。于是,从A点出发寻找两条不相交的道路到达B点,而且又只能往下和往右走,那么一定是在走了M+N-2步后到达B点,M是行数,N是列数。因为对于每一条线路来说,你要么往右走,要么往下走,那么从A到B需要往下走M-1步,往右走N-1步,加起来就是M+N-2步。那我从1迭代到M+N-2步,广搜搜出每一步有可能达到的所有点对组合不就行了么?确实是行的,比起第一个想法要实际得多,但仍然是非常耗时,因为在每一次的迭代当中,我有可能重复搜了同一个点对,这就导致了我在下一次迭代当中又有可能重复搜了另外一个点对,而且这种重复是呈指数增长的。为什么会重复?当有两个点对A和B都有可能达到同一个点对C时,我会把这个点对C重复加入到我下一次搜索的队列当中。那到底这个方法能不能AC呢?如果那个答案碰巧比较水的话,可能1s内就过了,如果是有点难度的话,可能就要跪了。

然后我也没想到好的方法了,因为我以前接触到的动规都是单线的,用一个二维表就过了的,根本就没往三维四维上面想,这说明“答案范”思想也是有利有弊的。思维的禁锢导致我不可能有更大空间的思考。为了解决上述广搜可能产生的重复问题,dp是必须的了,直到这时我才开始反省我是不是应该往更大胆的方面想象。我还是去看了别人题解,是四维的,有些改善了的是三维,开始我没看懂他们直接四维迭代为什么就能产生正确解,因为不是每一个点对都是可达的(为什么?自己思考下),不管某些点对是不是可达照样算权值,这样难道不会算错嘛?后面我思考了一下,“将错就错”其实也是一种提高速度的方法,因为无需你判断直接执行,节省了步骤自然就快。至于他们这种将错就错能不能算出正确答案我不知道,我从来就不会照搬别人代码。因此我还是按照了自己的思路来,下面贴出代码。

 #include<iostream>
using namespace std; bool IsPoss(int len,int x1,int x2,int M,int N); int main()
{
int M,N;
cin>>M>>N; int**V = new int*[M+];
for(int i=;i<=M;i++)
V[i] = new int[N+]; //获取权值
for(int i=;i<=M;i++)
for(int j=;j<=N;j++)
cin>>V[i][j]; //三维dp数组
int*** A = new int**[M+N-];
for(int i=;i<M+N-;i++)
{
A[i] = new int*[M+];
for(int j=;j<M+;j++)
A[i][j] = new int[M+];
} //初始条件
A[][][] = V[][]+V[][]; for(int i = ;i<M+N-;i++)
{
for(int x1=;x1<=M;x1++)
{
for(int x2=;x2<=M;x2++)
{
if(!IsPoss(i,x1,x2,M,N))
continue;
int min = -(int);
int y1 = i+-x1;
int y2 = i+-x2;
if(x1>&&x2>
&&IsPoss(i-,x1-,x2-,M,N)
&&A[i-][x1-][x2-]>min)
min = A[i-][x1-][x2-];
if(y1>&&y2>
&&IsPoss(i-,x1,x2,M,N)
&&A[i-][x1][x2]>min)
min = A[i-][x1][x2];
if(x1>&&y2>
&&IsPoss(i-,x1-,x2,M,N)
&&A[i-][x1-][x2]>min)
min = A[i-][x1-][x2];
if(x2>&&y1>
&&IsPoss(i-,x1,x2-,M,N)
&&A[i-][x1][x2-]>min)
min = A[i-][x1][x2-];
A[i][x1][x2] = min + V[x1][y1]+V[x2][y2];
}
}
} cout<<A[M+N-][M][M-]<<endl; //释放资源
for(int i=;i<=M;i++)
delete[] V[i];
delete[] V; for(int i=;i<M+N-;i++)
{
for(int j=;j<M+;j++)
delete[] A[i][j];
delete[] A[i];
}
delete[] A;
return ;
} /*
* 用来判断某一个点对是否合法,如果重叠了就不合法,会导致线路交叉的点对也不合法
*/
bool IsPoss(int len,int x1,int x2,int M,int N)
{
int y1 = len+-x1;
int y2 = len+-x2; if(y1<=||y2<=||y1>N||y2>N)
return false; if(x1==x2&&y1==y2)
return false; if(x1<x2&&y1>y2)
return false; return true;
}

思路如下:

转态转移方程:某一步的某一个可达点对的权值 = 前一步中能到达该点对中最大的点对的权值 + 该点对的权值。

那么用四维数组可以表示一个点对的权值:V[x1][y1][x2][y2]。但是假如步数已确定,x也确定,那么y也是唯一确定的,因此可以缩减到三维数组,用V[step][x1][x2]来表示在步数为step时,路线1到达了横坐标为x1,纵坐标为step-x1的点,路线2到达了横坐标为x2,纵坐标为step-x2的点(我以行为横坐标,列为纵坐标)。

由于我怕会混淆出错,我行和列都是从下标1开始迭代的。IsPoss函数用来判断某一个点对是否合法,不合法的直接跳过不计算。

Wikioi 1169 传纸条的更多相关文章

  1. 1169 传纸条 2008年NOIP全国联赛提高组 个人博客:attack.cf

    1169 传纸条 2008年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond         题目描述 Description 小渊和小轩 ...

  2. Codevs 1169 传纸条 2008年NOIP全国联赛提高组

    1169 传纸条 2008年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小渊和小轩是好朋友也是同班 ...

  3. codevs——1169 传纸条(棋盘DP)

    2008年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 小渊和小 ...

  4. Codevs 1169 == 洛谷 P1006 传纸条

    ---恢复内容开始--- 1169 传纸条 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小渊和小轩是好朋友也是同班同学,他 ...

  5. CodeVS1169 传纸条 [DP补完计划]

    题目传送门 题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端, ...

  6. codevs——T1169 传纸条

    http://codevs.cn/problem/1169/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 De ...

  7. tyvj1011 传纸条

    背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端, ...

  8. NOIP2008 传纸条

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

  9. NOIP2008传纸条[DP]

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

随机推荐

  1. C#开发客户端、JAVA和tomcat开发服务端

    hessian入门,Hello和文件上传范例,C#客户端+Java Tomcat后台 2.Hello范例1)后台--定义Java接口:package org.migle.hessian; public ...

  2. Dom4j解析xml格式的字符串【java】

    一般我们会使用dom4j.SAX.w3c来解析xml文件,网上也大多提供此类解决方案. 但在实际项目中,也有会解析xml格式的字符串报文的. 比如,有如下字符串: String = "< ...

  3. POJ 1300 欧拉通路&欧拉回路

    系统的学习一遍图论!从这篇博客开始! 先介绍一些概念. 无向图: G为连通的无向图,称经过G的每条边一次并且仅一次的路径为欧拉通路. 如果欧拉通路是回路(起点和终点相同),则称此回路为欧拉回路. 具有 ...

  4. 虚拟机IOS开发环境搭建教程

    来源:http://www.cnblogs.com/xiaoyaoju/archive/2013/05/21/3091171.html 安装条件: 硬件:一台拥有支持虚拟技术的64位双核处理器和2GB ...

  5. C++: int和string相互转换

    假设在一个C++的程序中常常会用到int和string之间的互换.个人建议能够写成一个函数,下次用的时候直接调用就可以. #include <iostream> #include < ...

  6. LeetCode227:Basic Calculator II

    Implement a basic calculator to evaluate a simple expression string. The expression string contains ...

  7. 跨服务器查询sql语句样例

    若2个数据库在同一台机器上:insert into DataBase_A..Table1(col1,col2,col3----)select col11,col22,col33-- from Data ...

  8. LDA-线性判别分析(三)

    本来是要调研 Latent Dirichlet Allocation 的那个 LDA 的, 没想到查到很多关于 Linear Discriminant Analysis 这个 LDA 的资料.初步看了 ...

  9. socket——本地服务器和android手机客户端通讯(防止中文乱码)

    线上效果图: 服务端接收到的. 客户端接受到服务器返回的. server端代码直接运行在本地就可以了. 手机客户端运行在手机上就行. 先安装客户端,再启动server.然后再输入文字,点击发送. se ...

  10. 修改sqlserver2008中表的schema

    schema类似命名空间,相同schema中不能有同样的表名,不用schema下可以有相同的表名 修改schema的方法: 在数据库的 安全性->架构 中添加一个新的架构 找到要修改的表,右击设 ...