HihoCoder第五周:标准动态规划

这周的题目是最标准最简单的动态规划了,自己一直以来对动态规划都不是很理解,这次也是好好记录一下。

题目1 :数字三角形

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

问题描述

Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋彼岸的美国。美国人民的生活非常有意思,经常会有形形色色、奇奇怪怪的活动举办,这不,小Hi和小Ho刚刚下飞机,就赶上了当地的迷宫节活动。迷宫节里展览出来的迷宫都特别的有意思,但是小Ho却相中了一个其实并不怎么像迷宫的迷宫——因为这个迷宫的奖励非常丰富~

于是小Ho找到了小Hi,让小Hi帮助他获取尽可能多的奖品,小Hi把手一伸道:迷宫的介绍拿来!

Ho选择的迷宫是一个被称为数字三角形n(n不超过200)层迷宫,这个迷宫的第i层有i个房间,分别编号为1..i。除去最后一层的房间,每一个房间都会有一些通往下一层的房间的楼梯,用符号来表示的话,就是从第i层的编号为j的房间出发会有两条路,一条通向第i+1层的编号为j的房间,另一条会通向第i+1层的编号为j+1的房间,而最后一层的所有房间都只有一条离开迷宫的道路。这样的道路都是单向的,也就是说当沿着这些道路前往下一层的房间或者离开迷宫之后,小Ho没有办法再次回到这个房间。迷宫里同时只会有一个参与者,而在每个参与者进入这个迷宫的时候,每个房间里都会生成一定数量的奖券,这些奖券可以在通过迷宫之后兑换各种奖品。小Ho的起点在第1层的编号为1的房间,现在小Ho悄悄向其他参与者弄清楚了每个房间里的奖券数量,希望小Hi帮他计算出他最多能获得多少奖券。

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为一个正整数n,表示这个迷宫的层数。

接下来的n行描述这个迷宫中每个房间的奖券数,其中第i行的第j个数代表着迷宫第i层的编号为j的房间中的奖券数量。

测试数据保证,有100%的数据满足n不超过100

对于100%的数据,迷宫的层数n不超过100

对于100%的数据,每个房间中的奖券数不超过1000

对于50%的数据,迷宫的层数不超过15(小Ho表示2^153万多呢,也就是说……

对于10%的数据,迷宫的层数不超过1(小Hi很好奇你的边界情况处理的如何?~

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要多。

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要少。

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的最多奖券数。

样例输入

5

2

6 4

1 2 8

4 0 9 6

6 5 5 3 6

样例输出

28

解题思路人家给得也真是详尽,关键代码都给了。。。

上代码:

#include <iostream>
using namespace std;

int reward[105][1005];
int best[105][1005]={0};
int n;

void Dongtai()
{
	int i,j;
	int result=0;

	for(i=1;i<=n;i++)
	{
		for(j=1;j<=i;j++)
		{
			best[i][j]=max(best[i-1][j],best[i-1][j-1])+reward[i][j];
		}
	}

	for(i=1;i<=n;i++)
	{
		if(best[n][i]>result)
			result= best[n][i];

	}
	cout<<result<<endl;
}
int main()
{
	int count1,count2;
	
	cin>>n;

	for(count1=1;count1<=n;count1++)
	{
		for(count2=1;count2<=count1;count2++)
		{
			cin>>reward[count1][count2];
		}
	}
	Dongtai();

	return 0;

}


且不说深度优先这样一个最坏情况下仍然有问题的方法,我们来说这个宽度优先搜索,我们能够使用best(i, j)来进行优化,无非是因为这个问题存在这样两个性质。Hi道。

第一便是无论我是通过怎么样的方式到达第i层第j个房间的,我之前做出的选择不会对我之后的选择做出限制与优待。就像如果我规定至少要向右走3次,那么状态就不仅仅是(i, j, k)这样,还要加上一个已经向右走的次数t,那么你觉得还能就直接像我们之前的方法进行计算么?如果到达第i层第j个房间的路上向右走过3次了,那么之后的走法就没有任何限制,不然就仍会有一个至少要向右走一定次数的限制。这样对于两个状态(i, j, k, l)(i, j, k', l'),我们就不能够直接判断出那个状态是更加好的。

没错~其实就是best(i, j)有两个关键字进行参考,而这样的话就不是任意两个状态都可以进行比较的了。Ho总结道。

这样的性质被我们称为无后效性,顾名思义,当前的抉择不会对后面抉择产生影响。

那第二个性质呢?

第二个性质被我们称为重复子问题,在我们之前的例子中,我们将从起点出发到走出迷宫的最优路分解成了两个子问题,其一是从第2层的第1个房间走出迷宫的最优路,其二是从第2层的第2个房间走出迷宫的最优路,只要能算出这两个部分的最优值,我就可以知道从起点出发到走出迷宫的最优路。Hi道:而按照这样的方法,这两个子问题都有一个相同的子问题——从第3层的第2个房间出发走出迷宫的最优路。

这就是重复的子问题了,而我们的做法就是,重复的子问题只计算一次!也就是说我们要先计算出从起点到达第3层的第2个房间的最优线路,然后再考虑接下来怎么走~”Ho感觉自己渐渐的把握到了关键之处

 

动态规划的两个特性:无后效性和重复子问题,渐学渐领教。毕竟后面还有更难的动态规划题目。加油,你本是一位诗人。

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted on 2015-05-04 17:01  光速小子  阅读(302)  评论(0编辑  收藏  举报

导航