数塔问题

如图所示:


问题描述:上图所示,从顶层出发,在每一个节点上,只能往相邻节点走(即向左或者向右), 一直走到最底层, 要求找到一条途径,使路径之和最大?


从顶点出发时到底向左走还是向右走应取决于是从左走能取到最大值还是从右走能取到最大值, 只要左右两道路径上的最大值求出来了才能作出决策。 同样的道理下一层的走向又要取决于再下一层上的最大值是否已经求出才能决策。 这样一层一层推下去,直到倒数第二层时就非常明了。用DP来考虑,从底自上,计算即可。


转移方程:sum[i] = max(a[左孩子] , a[右孩子]) + a[i]


求最优值:

// shuta_problem.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>

using namespace std;

#define  N  5


int _tmain(int argc, _TCHAR* argv[])
{
	int i, j;
	int data[N][N] = { 
		9, 0, 0, 0, 0,
		12, 15, 0, 0, 0,
		10, 6, 8, 0, 0,
		2, 18, 9, 5, 0,
		19, 7, 10, 4, 16
	};



	for (i = N-1; i > 0; i--)
		for (j = 0; j < i; j++)
		{
			data[i-1][j] +=  data[i][j] > data[i][j+1] ? data[i][j] : data[i][j+1];

		}

		cout << data[0][0];


		return 0;
}

得出的结果为:59


以下为求最优解:


// shuta_problem.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <fstream>

using namespace std;

#define  N  5


int _tmain(int argc, _TCHAR* argv[])
{
	int i, j;
	int fdata;
	bool sign = true;
	int data[N][N][3];   //[0]用来存数, [1]参与计算,[2]表示方向,(0)表左, (1)表右

	ifstream fin("data.txt", ios::in);
	ofstream fout("out.txt" , ios::app);

	if(!fin)
		cout << "error";


	//读取数据
	for ( i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			fin	 >> data[i][j][0];
			data[i][j][1] = data[i][j][0];
			data[i][j][2] = 0;	

		}
	}


	for (i = N - 1; i > 0; i--)
		for (j = 0; j < i; j++)
		{
			if (data[i][j][1] > data[i][j+1][1])  //左边大
			{
				data[i][j][2] = 0;
				data[i-1][j][1] += data[i][j][1];
			}
			else                                 //右边大
			{
				data[i][j][2] = 1;
				data[i-1][j][1] += data[i][j+1][1];
			}
		}



		//输出数塔
		for ( i = 0; i < N; i++)
		{
			for (j = 0; j <= i; j++)
			{
				cout << data[i][j][1] << "   ";
			}

			cout << endl;

		}

		//输出最优值
		cout << "数塔最大值为: "<< data[0][0][1] << endl;
		fout << "数塔最大值为: "<< data[0][0][1] << endl;

		//输出路径
		for (i = 0, j = 0; i < N; i++)
		{
			cout << "[" << i <<" , "<< j <<"]" <<"->";
			fout << "[" << i <<" , "<< j <<"]" <<"->";
			j += data[i+1][j][2];
		}


		
		fin.close();
		fout.close();





		return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值