算法基础--动态规划1

在之前学习分治时,我们曾提及很多时候使用分治(递归)的方式解决问题时会导致大量重复计算,导致时间复杂度非常高,而多数情况下解决这种情况的办法就是动态规划,下面给一个例子:

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

在给出的形如上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往正下或右下走。只需要求出这个最大和即可,不必给出具体路径。三角形的行数大于1小于等于100,数字为 0 - 99

输入格式:
5 //三角形行数。下面是三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出格式: 输出最大和即可
解题思路:首先,容易想到顶部到底部的最大和路径等于MAX{顶部正下方元素到底部路径的最大和,顶部右下方元素到底部路径的最大和},这显然是一个递归形式的命题,设函数MaxSum(i,j)表示(i,j)位置元素到底部路径的最大和,则有
MaxSum(i,j)=MAX{ MaxSum(i+1,j),MaxSum(i+1,j+1)},容易写出程序:

#include 
#include  
using namespace std;
int D[101][101];
int n;
int MaxSum(int i,int j)
{
	if(i==n) return D[i][j];
	int x=MaxSum(i+1,j);
	int y=MaxSum(i+1,j+1);
	return max(x,y)+D[i][j];
}
int main()
{
	cin >> n;
	for(int i=0;i> D[i][j];
		}
	}
	cout << MaxSum(0,0);
	return 0;
}

本解法看起来十分明了,逻辑上似乎可以得出正确答案,但细细分析会发现里面包含着大量重复计算,在计算第二行第一个数字和第二个数字到底部的路径最大和时,第三行的第二个位置要被计算两次,依次类推,再下一层的位置会被重复计算更多次,那么这个算法的时间复杂度是多少呢,简单推算可得到出其时间复杂度为O(2n),当问题规模来到n=100时,此时时间复杂度为2100 !显然,这不是个相当合理的算法。

那么,如何设计方案可以合理的解决该问题呢

首先,递归的思想并没有错,问题的关键在于避免重复计算,所以就有了一种想法,将已经计算出的值保存起来,下次要用时直接使用该值,实际上这就是动态规划

下面给出动态规划解决该问题的代码:

#include 
#include 
using namespace std;
int D[101][101];
int n;
int Maxm[101][101];
int MaxSum(int i,int j)
{
	if(Maxm[i][j]!=-1) return Maxm[i][j];
	if(i==n) Maxm[i][j]=D[i][j];
	else
	{
		int x=MaxSum(i+1,j);
		int y=MaxSum(i+1,j+1);
		Maxm[i][j]=max(x,y)+D[i][j];
	}
	return Maxm[i][j];
}
int main()
{
	cin >> n;
	for(int i=0;i> D[i][j];
			Maxm[i][j]=-1;
		}
	}
	cout << MaxSum(0,0);
	return 0;
} 

这里使用数组Maxm[i][j]来存储递归过程中算出的结果,避免了大量的重复计算,此时的时间复杂度为O(n2

另外,动态规划方法也可以用递推(迭代)的方式来实现,一般来说这种方式要比递归好一些
对于本题而言,递归的运行过程类似一个从顶部到底部的入栈再出栈的过程,而实际上计算机中实现递归就是通过栈完成的。
而迭代方式则是要从底层数字开始,先算出较低层到底层的路径最大和,再利用该层的计算结果结算高一层到底层的路径最大和

下面给出迭代实现程序:

#include 
#include 
using namespace std;
int main()
{
	int d[101][101];
	int n;
	cin >> n;
	for(int i=0;i> d[i][j];
		}
	}
	for(int i=n-2;i>=0;i--)
	{
		for(int j=0;j<=i;j++)
		{
			d[n-1][j]=max(d[n-1][j],d[n-1][j+1])+d[i][j];
		}
	}
	cout << d[n-1][0];
	return 0;
}

这里使用了原来的数组存储计算结果,因为使用迭代方法时,一层的数字参与运算后就不用再参与其余运算,所以我们把计算每层的计算结果都存储在原数组的最后一层,最后顶层到底层的路径最大和就被存在了最后一层的第一个位置上。这种空间优化的方式在迭代式动态规划中很常用。

你可能感兴趣的:(算法)