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

刚接触到这道题的时候我第一反应是单线的动规,可是下一秒我就觉得这样做可能会有问题,因为从左上角(以下简称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. Search in Rotated Sorted Array (I, II) 解答

    Question Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 ...

  2. 【HDU1875】畅通工程再续(MST基础题)

    更改成实形数即可.第一次敲完直接交,CE了一次.晕. #include <iostream> #include <cstring> #include <cstdio> ...

  3. python 给lambda命名(网友处学习)

    from os import * def set_name(**k): assert len(k)==1 name,obj=k.items()[0] obj.func_name=name return ...

  4. PHP操作MySQL数据库的相关函数

    首先,要分清SQL语句的类型: SQL语句的分类 (1)DDL:Data Define Language,数据定义语言--定义表的列结构 CREATE.DROP.ALTER.TRUNCATE (2)D ...

  5. linux学习方法之二

    相信不少想学习linux的新手们正愁不知道看什么linux学习教程好,下面小编给大家收集和整理了几点比较重要的教程,供大家学习,如需想学习更多的话,可到wdlinux学堂寻找更多教程. 安装php扩展 ...

  6. HDU 1085 Holding Bin-Laden Captive! (母函数)

    Holding Bin-Laden Captive! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  7. Docker快速搭建neural style环境

    ## 概览 相关的代码都在Github上,请参见我的Github,https://github.com/lijingpeng/neural-style 敬请多多关注哈~~~ ## Docker镜像构建 ...

  8. 一道movfuscator混淆过的简单逆向

        月赛中出了道经过movfuscator混淆的逆向题目,记录一下过程.跑起来发现需要用户输入长度为20的字符串,我尝试着输入了几次都是直接退出了,没有任何提示.用IDA打开,题目里面几乎全是mo ...

  9. Hacker(13)----搜集目标计算机的重要信息

    扫描与嗅探攻防 黑客若要发起入侵攻击,他需要做好充分的准备的工作,首先通过嗅探和扫描等操作来搜索信息,从而确定目标计算机,以便准确发出攻击.嗅探和扫描操作可以利用专业的软件工具实现,如X-Scan.S ...

  10. 涂抹Oracle笔记1-创建数据库及配置监听程序

    一.安装ORACLE数据库软件及创建实例OLTP:online transaction processing 指那些短事务,高并发,读写频繁的数据库系统.--DB_BLOCK_SIZE通常设置较小.O ...