例3《硬幣收集問題》
問題描述:
在N x M格木板中放有一些硬幣,每格的硬幣數目最多為一個。在木板左上方的一個機器人需要收集盡可能多的硬幣並把它們帶到右下方的單元格。每一步,機器人可以從當前的位置向右移動一格或向下移動一格。當機器人遇到一個有硬幣的單元格時,就會將這枚硬幣收集起來。設計一個算法找出機器人能找到的最大硬幣數。
分析:
1.令F(i,j)為機器人截止到第i行第j列單元格(i,j)能夠收集到的最大硬幣數。單元格(i,j)可以經由上方相鄰單元格(i-1,j)或者左邊相鄰單元格(i,j-1)到達。單元格(i-1,j)和單元格(i,j-1)中最大的硬幣數目分別是F(i-1,j)和F(i,j-1)。當然,第一行單元格沒有上方相鄰單元格,第一列單元格沒有左邊相鄰單元格。對這些單元格,我們假定F(i-1,j)或F(i,j-1)的值為0,因為其不存在相應的相鄰單元格。因此,截止到單元格(i,j)機器人能夠收集到的最大硬幣數是這兩個數的較大值加上單元格(i,j)中可能存在的一枚硬幣。
2.遞推公式為:
代碼:
package algorithm; public class demo_1 { //輸出找到最大硬幣數的路徑 public void getMaxPath(int[][] A){ int rowA = A.length; int columnA = A[0].length; //在數組A最上面一行添加一行元素0,在最左邊一列添加一列元素0 int[][] changeA = new int[rowA+1][columnA+1]; //初始化,各個元素均為0 int[][] maxA = new int[rowA+1][columnA+1]; //用於計算從A[0][0]到達各元素位置收集到的最大硬幣數 for(int i = 0;i < rowA;i++){ for(int j = 0;j < columnA;j++) changeA[i+1][j+1] = A[i][j]; } for(int i = 1;i <= rowA;i++){ for(int j = 1; j <= columnA;j++){ if(maxA[i-1][j] >= maxA[i][j-1]) maxA[i][j] = maxA[i-1][j] + changeA[i][j]; else maxA[i][j] = maxA[i][j-1] + changeA[i][j]; } } //輸出各個元素位置收集到的最大硬幣數 System.out.println("各個元素位置收集到的最大硬幣數:"); for(int i = 1;i <= rowA;i++){ for(int j = 1;j <= columnA;j++) System.out.print(maxA[i][j]+"\t"); System.out.println(); } } public static void main(String[] args){ demo_1 test = new demo_1(); int[][] A ={{0,0,0,0,1,0}, {0,1,0,1,0,0}, {0,0,0,1,0,1}, {0,0,1,0,0,1}, {1,0,0,0,1,0}}; test.getMaxPath(A); } }
3.測試數據:
int[][] A ={{0,0,0,0,1,0},
{0,1,0,1,0,0},
{0,0,0,1,0,1},
{0,0,1,0,0,1},
{1,0,0,0,1,0}};
結果:
各個元素位置收集到的最大硬幣數:
0 0 0 0 1 1
0 1 1 2 2 2
0 1 1 3 3 4
0 1 2 3 3 5
1 1 2 3 4 5