一、數值三角形中的最大路徑
隨機產生一個n行的點數值三角形(該數值三角形的第K行有K個點,每一個點都帶有一個正整數),,即隨機產生一個7行點數值三角形。尋找從頂點開始每一步可沿左斜(L)或右斜(R)向下直至底部的一條路徑,使該路徑所經過的點的數值和最大。
16
12 13
8 12 7
14 9 17 5
6 18 18 13 13
11 8 8 3 15 8
7 1 18 5 2 17 19
二、數值三角形中的最大路徑搜尋
應用動態規劃,採用逆推法即從底向上逐行反推。
隨機產生的點數值三角形的數值在二維數組a(n, n)中,同時賦給b(n, n)。 這裡數組b(i, j)為點i(i, j)到底的最大數組和,stm(i,j)是點(i,j)向左或向右的路標字元數組,實施逆推法,知b(i,j)與stm(i,j)(i=n-1,...,2,1)的值由b的第i+1行的值決定:
若b(i+1, j+1) > b(i+1, j),則
b(i, j)=b(i,j)+b(i+1,j+1);stm(i,j)="R"
若b(i+1,j+1) <= b(i+1,j),則
b(i, j)=b(i,j)+b(i+1,j); stm(i,j)="L"
這樣所得b(1,1)即為所示的最優路徑數值和。
為了列印最優路徑,利用stm數組從上而下尋找:先列印a(1,1),若stm(1,1)='R',則下一個列印a(2,2),否則列印a(2,1)。一般地,對i=2,3,...,n:
若stm(i-1, j)="R",則列印“-R”;a(i,j+1);同時賦值j++。
若stm(i-1, j)="L",則列印"-L-";a(i,j);
依此列印出最大路徑。
三、代碼實現
// 求最優路徑程式設計(-)<br />// 利用動態規劃,求點數值三角形的最優路徑<br />#include <stdio.h><br />#include <stdlib.h><br />#include <time.h></p><p>int main(void)<br />{<br />int i, j, nRow;<br />int a[30][30], b[30][30];<br />char stm[30][30];</p><p>printf("請輸入行數Row:");<br />scanf("%d", &nRow);<br />// 初始化隨機數種子<br />srand(time(NULL));</p><p>// 輸出n行的點數值三角形<br />for (i = 1; i <= nRow; i++) {<br />for (j = 1; j <= 40 - 2 * i; j++)<br />printf(" ");<br />for (j = 1; j <= i; j++) {<br />a[i][j] = rand() % 20 + 1;<br />b[i][j] = a[i][j];<br />printf("%4d", a[i][j]);<br />}<br />putchar('/n');<br />}</p><p>// 逆推求取最大值<br />for (i = nRow - 1; i >= 1; i--)<br />for (j = 1; j <= i; j++) {<br />if (b[i + 1][j + 1] > b[i + 1][j]) {<br />b[i][j] = b[i][j] + b[i + 1][j + 1];<br />stm[i][j] = 'R';<br />}<br />else {<br />b[i][j] = b[i][j] + b[i + 1][j];<br />stm[i][j] = 'L';<br />}<br />}</p><p>printf("/n最優路徑數值和為:%d", b[1][1]);<br />printf("/n最優路徑為:%2d", a[1][1]);<br />j = 1;// 按中標引導輸出最優路徑<br />for (i = 2; i <= nRow; i++)<br />if (stm[i - 1][j] == 'R') {<br />printf("-R-%2d", a[i][j + 1]);<br />j++;<br />}<br />else<br />printf("-L-%2d", a[i][j]);</p><p>return 0;<br />}
四、數值矩陣中的最小路徑搜尋
問題描述:隨機產生一個n行m列的整數矩陣,即隨機產生的一個7行5列的數值矩陣,在整數矩陣中尋找從左上方至右下角,每步可向下(D)或向右(R)或斜向右下(O)的一條數值和最小的路徑。
27 28 29 18 26
16 13 19 14 27
32 22 39 26 21
10 30 23 20 18
13 11 30 29 20
10 13 21 17 36
34 37 15 22 36
設計要點:應用動態規劃設計,即從右下角逐行反推左上方。確定n、m後,隨機產生的整數二維數組a(n,m)作矩陣輸出,同時賦給部分和數組b(n, m)。
這裡數組b(i,j)為點(i,j)到右下角的最小數值和,stm(i,j)是點(i,j)向右(R)或向下(D)或向右下(O)的路標字元數組。
注意到最後一行與最後一列各數只有一個出口,於是由b(n,m)開始向左逐個推出同行的b(n,j)(j=m-1,...,2,1);向上逐個推出同列的b(i,m)(i=n-1,...,2,1)。
b(i,j)與stm(i,j) (i=n-1,...,2,1; j=m-1,...,2,1)的值由同一列其下面的整數b(i+1,j)與同一行其右邊的整數b(i,j+1)或其右下方的b(i+1,j+1)的值決定:
設min=min(b(i+1,j+1),b(i,j+1),b(i+1,j);
首先,作賦值min=b(i+1,j+1),stm(i,j)="O";
若b(i,j+1)<min,則min=b(i,j+1),stm(i,j)="R";
若b(i+1,j)<min, 則min=b(i+1,j),stm(i,j)="D"。
然後賦值:b(i,j)=b(i,j)+min。
這樣反推所得b(1,1)即為所求的最小路徑數字和。
為了列印最小路徑,利用c數組從上而下操作:先列印a(1,1), i=1, j=1.
①若stm(i,j)="R",則j++,然後列印"-R-"與右邊的整數a(i,j)。
②若stm(i,j)="D",則i++,然後列印"-D-"與下面的整數a(i,j)。
③若stm(i,j)="O",則i++,j++,然後列印"-O-"與斜右下的整數a(i,j)。
依次類推,直到列印到點a(n,m)。
代碼實現:
// 求最優路徑程式設計(-)<br />// 利用動態規劃,求數值矩陣左上方至右下角最小路徑<br />#include <stdio.h><br />#include <stdlib.h><br />#include <time.h></p><p>int main(void)<br />{<br />int m, n, row, col, min;<br />int a[30][30], b[30][30];<br />char stm[30][30];</p><p>printf("請輸入行數與列數n和m:");<br />scanf("%d%d", &n, &m);<br />// 初始化隨機數種子<br />srand(time(NULL));</p><p>// 產生並輸出n行m列的數值矩陣<br />for (row = 1; row <= n; row++) {<br />putchar('/n');<br />for (col = 1; col <= m; col++) {<br />a[row][col] = rand() % 40 + 5;// 5~44的隨機數<br />b[row][col] = a[row][col];<br />printf("%4d", a[row][col]);<br />}<br />}</p><p>// 第n行遞推為邊界條件<br />for (col = m - 1; col >= 1; col--) {<br />b[n][col] = b[n][col] + b[n][col + 1];<br />stm[n][col] = 'R';<br />}<br />// 第m列遞推為邊界條件<br />for (row = n - 1; row >= 1; row--) {<br />b[row][m] = b[row][m] + b[row + 1][m];<br />stm[row][m] = 'D';<br />}</p><p>// 逆推求取最大值b(1,1)<br />for (row = n - 1; row >= 1; row--)<br />for (col = m - 1; col >= 1; col--) {<br />min = b[row + 1][col + 1];<br />stm[row][col] = 'O';<br />if (min > b[row + 1][col]) {<br />min = b[row + 1][col];<br />stm[row][col] = 'D';<br />}<br />if (min > b[row][col + 1]) {<br />min = b[row][col + 1];<br />stm[row][col] = 'R';<br />}<br />b[row][col] = b[row][col] + min;<br />}</p><p>printf("/n最優路徑數值和為:%d", b[1][1]);<br />printf("/n最優路徑為:%2d", a[1][1]);<br />row = 1; col = 1;// 按路標引導輸出最優路徑<br />while (row < n || col < m) {<br />switch (stm[row][col]) {<br />case 'R':<br />col++;<br />printf("-R-%d", a[row][col]);<br />break;<br />case 'D':<br />row++;<br />printf("-D-%d", a[row][col]);<br />break;<br />case 'O':<br />row++;<br />col++;<br />printf("-O-%d", a[row][col]);<br />break;<br />}<br />}<br />putchar('/n');</p><p>return 0;<br />}
轉自《趣味C程式設計集錦》