數字三角形(C語言)
一、問題描述
給定一個由行數字組成的數字三角形。試著設計一個演算法,計算出從三角形的頂到底的一條路徑,使得該路徑經過的數字總和最大,並分析演算法的計算複雜性。如下圖所示:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
二、問題分析及演算法描述(包含主要變數和函式功能介紹)
設a(i,j)表示數字三角形中的第i行第j個點。 max[i][j]表示第i行第j個數字到低端的最佳路徑之和,則原問題的解就是max[1][1]的值了。 從a(i,j)這個點向下走,顯然只能走a(i+1,j)和a(i+1,j+1)這兩個點了。而max[i][j]的最優值=a(i,j)的值+max{. max[i+1][j],max[i+1][j+1] }o 所以,我們可以至底向,上來計算。先計算最後一層的點的,然後倒二層的,…一直算到第一層。
遞推方程:
三、源程式及程式說明檔案
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;-·
int a[110][110];
int max[110][110];
int n;
int MaxSum(int n)
{
for (int i = n; i >= 1; i--)
{
max[n][i] = a[n][i];//初始化,最下面一層的max陣列就是三角形最下面一層的值
}
for (int i = n - 1; i >= 1; i--)
{//從倒數第二層向上計算
for (int j = 1; j <= i; j++)
{//計算第 i 層的每一個點的 max[][]
if (max[i + 1][j + 1]>max[i + 1][j])
{
max[i][j] = max[i + 1][j + 1] + a[i][j];//要麼向下一層上和它最近的右邊走
}
else
max[i][j] = max[i + 1][j] + a[i][j];//要麼向下一層上和它最近的左邊走
}
}
return max[1 ][1];
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= i; j++)
{
cin >> a[i][j];
}
}//構造數字三角形
cout << MaxSum(n) << endl;
int k = 1;
for (int i = k; i <= n; i++)
{
cout << a[i][k] << " ";
if (max[i + 1][k + 1] + a[i][k] > max[i + 1][k] + a[i][k])
{
k = k + 1;
}
}//列印路徑
return 0;
}
四.證明數字三角形的最優子結構性質。
證:
原問題:MAX[i,j] 最優解 L[n]
子問題:MAX[i+1,j+1] 最優解 L’[n]
反證法:設L’[n] 不為子問題的最優解,令M’[n]為子問題的最優解
則M’[n]<L’[n]
所以 M’[n]+L[n-1]<L’[n]+L[n-1]=L[n]
與L[n]為原問題的最優解相矛盾,即證!
五、答案顯示
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
30
7 3 8 7 5
六、演算法分析(T(n)和S(n))
本程式為遞推型動歸程式,由底向上遞推,除最後一行外,每一行的每個點
最頂部即為所求。其三角形的數字總和為 n(n + 1)/2,演算法的時間複雜度 T(n) = O(n^2),空間複雜度與n成線性比例關係,即其空間複雜度 S(n) = O(n);
七、課程設計總結
通過本次課程設計和實際操作,對於動態規劃有了更好的的理解,尤其是對最優子結構的認識更加深刻,從中學到了許多新的程式設計思想。知道了如何更好地設計演算法很大的提高了程式設計效率。
在解決本次題目—數字三角形中出現了一些因為粗心而出現的問題,經過小組討論和一反除錯最終將所有問題解決。實驗的成功離不開小組三人的合作以及老師的指導,本次試驗不僅在演算法問題上收穫頗豐,並且因為小組三人的通力協作,加深了對此次問題的理解和學習。