1. 程式人生 > >動態規劃之數塔問題

動態規劃之數塔問題

  1. 教材習題6第1題。

有數字三角形如下:

找出從第一層到最後一層的一條路,使得所經過的權值之和最小或者最大。

#include<iostream>
using namespace std;

const int N=50;

int main()
{
	cout << "Please input N(lines): " ;
	//數塔的層數
	int n;
	cin >> n;
 
	int d[N+1][N+1][3];	//[1]用來存數,[2]參與運算,[3]表示向左(0),還是向右(1)
	//輸入數塔
	for(int i = 1; i <= n; ++i)
	{
		cout << "Please input line"<< i<<": ";
		for(int j = 1; j <= i; ++j)		//第i行有i個數
		{
			cin >> d[i][j][1];
			d[i][j][2] = d[i][j][1];
			d[i][j][3] = 0;
		}
	}
	cout << endl;
	for( i = n-1; i >= 1; --i)	//從倒數第二行開始
	{
		for(int j=1; j <= i; j++)
		{
			if (d[i+1][j][2] > d[i+1][j+1][2])	
			{
				d[i][j][2] += d[i+1][j][2];
				d[i][j][3] = 0;	
			}
			else	
			{
				d[i][j][2] += d[i+1][j+1][2];
				d[i][j][3] = 1;	
			}
		}
	}	
	//輸出數塔
	for( i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cout << d[i][j][1] << " ";
		}
		cout << endl;
	}
	cout << "Max:"<<d[1][1][2] << endl;
	//輸出路徑
	int j;
	for(i = 1, j = 1; i<= n; ++i)
	{
		cout << "[" << i << "," << j << "]" << " -> ";
		j += d[i][j][3];
	}
	cout << "結束"<<endl;
	return 0;
}

結果如下:

提示:

所經過的權值之和最大值為例進行說明。

行進的過程中,每次只有兩種選擇:向左或向右。一個有n層的數字三角形的完整路徑有2n條,所以當n比較大的時候,搜尋全部路徑,從中找出最大值,效率較低。

採用動態規劃方法實現。

d(i,j)表示從位置(i,j)出發時得到的最大值(包括位置(i,j)本身),可以寫出最大值的遞迴方程:

由於遞迴方程中包含了重複子問題,直接採用遞迴方程求解, 效率較低。採用動態規劃的方法,用一張二維表記錄中間過程的值,可以把時間效率提高到n2。