如图所示:
问题描述:上图所示,从顶层出发,在每一个节点上,只能往相邻节点走(即向左或者向右), 一直走到最底层, 要求找到一条途径,使路径之和最大?
从顶点出发时到底向左走还是向右走应取决于是从左走能取到最大值还是从右走能取到最大值, 只要左右两道路径上的最大值求出来了才能作出决策。 同样的道理下一层的走向又要取决于再下一层上的最大值是否已经求出才能决策。 这样一层一层推下去,直到倒数第二层时就非常明了。用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;
}