閱讀65 返回首頁    go 技術社區[雲棲]


poj 1163 The Triangle【dp】

和POJ3176幾乎一模一樣,(隻有row的範圍不同,其實可以不用改的,我還是改了一下),連給的數據都一樣,都是最簡單的那個 dp 動歸問題


AC的代碼:


#include<stdio.h>

int dp[102][102];

inline int max(int a,int b){return a>b?a:b;}

int main()
{
    int n,i,j;

    scanf("%d",&n);

	//輸入
    for(i=1;i<=n;i++)
        for(j=1;j<=i;j++)
            scanf("%d",&dp[i][j]);

	//dp
    for(i=n-1;i>=1;i--)
        for(j=1;j<=i;j++)
            dp[i][j]=max(dp[i][j]+dp[i+1][j],dp[i][j]+dp[i+1][j+1]);

    printf("%d\n",dp[1][1]);

    return 0;
}


轉過來一個寫的還不錯的貼



問題描述:輸入一個數字三角形

                                   7
                                3   8
                               8  1   0
                             2  7   4   4
                          4   5   2   6   5

                            (Figure 1)

        如Figure 1所示一樣,在上麵的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所經過的數字之和最大。路徑上的每一步都是能往左下或右下走。隻需要求出最的和即可,不需要輸出路徑。

解題思路:算法一 、遞歸思想

         設f(i,j) 為三角形上從點(i,j)出發向下走的最長路經,則 f(i,j) =max(f(i 1,j), f(i 1,j 1))
要輸出的就是f(0,0)即從最上麵一點出發的最長路經。

          以D(r, j)表示第r行第 j 個數字,以MaxSum(r, j) 代表從第 r 行的第 j 個數字到底邊的各條路徑中,數字之和最大的那條路徑的數字之和,則本題是要求MaxSum(0,0)。(假設行編號和一行內數字編號都從0開始)。
典型的動態規劃問題。
從某個D(r, j)出發,顯然下一步隻能走D(r 1,j)或者D(r 1, j 1),所以,對於N行的三角形:
                     if ( r == N-1 )    
                          MaxSum(r,j) = D(N-1,j)
                     else 
                          MaxSum(r, j) = Max(MaxSum(r 1,j),MaxSum(r 1,j 1) ) D(r,j);

 代碼如下:

#include <iostream.h> 
#define MAX 101 
int triangle[MAX][MAX]; 
int n; 
int longestPath(int i, int j); 
void main(){ 
 int i,j; 
 cin >>n; 
 for(i=0;i<n;i) 
 for(j=0;j<=i;j ) 
   cin>> triangle[i][j]; 
 cout <<longestPath(0,0) << endl; 

int longestPath(int i, int j){ 
 if(i==n-1)return triangle[i][j]; 
 int x =longestPath(i 1,j); 
 int y =longestPath(i 1,j 1); 
    if(x<y) x=y; 
    return x triangle[i][j]; 
}        
     (超時!!!!)

為什麼會超時呢?

   答:如果采用遞規的方法,深度遍曆每條路徑,存在大量重複計算,則時間複雜度為 2n,對於 n = 100,肯定超時。

一種可能的改進思想:從下往上計算,對於每一點,隻需要保留從下麵來的路徑中和最大的路徑的和即可。
    因為在它上麵的點隻關心到達它的最大路徑和,不關心它從那條路經上來的。
   問題:有幾種解法??
        從使用不同的存儲開銷角度分析
            2?00?00譻izeof(int)
            (100?00 100)譻izeof(int)
            100譻izeof(int)

  解法一、
  如果每算出一個MaxSum(r,j)就保存起來,則可以用o(n2)時間完成計算。因為三角形的數字總數是n(n 1)/2
此時需要的存儲空間是:
int D[100][100]; //用於存儲三角形中的數字
int Sum[100][100]; //用於存儲每個MaxSum(r,j)

 

  解法二、

   沒必要用二維Sum數組存儲每一個MaxSum(r,j),隻要從底層一行行向上遞推,那麼隻要一維數組Sum[100]即可,即隻要存儲一行的MaxSum值就可以。比解法一改進之處在於節省空間,時間複雜度不變。

 

   解法三、

   能否不用二維數組D[100][100]存儲數字呢?
思路:倒過來考慮。前麵的思路是從底往上最終算出MaxSum(0,0)。如果從頂往下算,最終算出每一個MaxSum(N-1,j),然後再取最大的MaxSum(N-1,j),不就是答案嗎?此時遞推公式為:
                 if( r == 0 )
                    MaxSum(r,j) = D[0][0];
                else
                 MaxSum(r,j) = Max(MaxSum(r-1,j-1), MaxSum(r-1,j)) D[r][j];
 由於兩重循環形式為:
 for( r = 0 ; r < N ; r ) 
  for( j = 0 ; j < r 1 ; j ) {
  ………..
 } 
 r,j不斷遞增,所以實際上不需要D[100][100]數組,每次從文件裏讀取下一個數字即可。
 而每一行的每個MaxSum(r,j)仍然都需要存儲起來,這樣,隻需要一個Sum[100]數組。
(注:隻需設一個臨時存儲變量,在計算MaxSum(r,j)後寫入數組時,暫存MaxSum(r-1,j))


  解法四:

   也就是本人所執行的算法,它是基於解法三中“從上往下”的思想,每輸入一個數後臨時存起來,然後用一個sum[i]來存放該處的最大路徑和數,由於所輸入的數字三角是成一個以1為公差的等差數列,充分利用其變量間的一種親密關係,成功實現並不困難。具體的算法如下:

#include <iostream>
using namespace std;
int main(){
   int sum[5051]={0};       //聲明用來存放數據的數組,sum=(n^2+n)/2 max(sum)=5050(n==100) 
   int n,r,j,num,i=1,max=0;     //r表變化的行數, 
  cin>>n;                //輸入數據行數 
   for(r=1;r<=n;r++){         
          for(j=1;j<=r;j++,i++){   
          scanf("%d",&num);        //輸入三角形數據 
          if(j==1){sum[i]=num+sum[i-r+1];continue;}    //輸入的是每行的第一個數 
          if(j==r)sum[i]=num+sum[i-r];               //輸入的是每行中的最後一個數 
           else sum[i]=(sum[i-r]>sum[i-r+1]?sum[i-r]:sum[i-r+1])+num;    //輸入的是中間數時 
      }                 
   }
   /*for(j=1;j<i;j++)cout<<sum[j]<<"";   //測試用來輸出每個點上所對應的最大路徑和數 
   cout<<endl;
   */
  for(j=1;j<i;j++)            //尋最大路徑和數 
        if(sum[j]>max)max=sum[j];
  cout<<max<<endl;
  system("pause");
  return 0;

  心得:經過解此題,讓我走出了一個算法的局限誤區,思維進一步得到了提高,之前遇到一個類似的題,當初就受思維的局限心想要用到搜索,或者是有關圖的遍曆才能解決的問題,沒想到如今卻隻要區區幾十行代碼就解決了。“規律往往是掌握在有一雙“狠”的眼睛的人的大腦裏!”從而得出了這樣一句話來收場。

 


最後更新:2017-04-03 14:53:41

  上一篇:go pthread創建RR線程
  下一篇:go oracle 不是group by表達式