1. 程式人生 > >hello_cosmos的專欄

hello_cosmos的專欄

還是動態規劃

題目大意:

給定一個N*N的矩陣,在矩陣中尋找一個h*w的矩陣,使得對於所有可能的矩陣,這個矩陣的所有元素和最大,並輸出這個最大值。

-------------------------------------------------割啊割啊割啊割啊割啊割------------------------------------------------------

額,一開始呢,我覺得這是一道蠻有挑戰性的題目...結果...

其實一開始我還是分析了這題目的子結構什麼的,結果發現,這道題可以直接轉換成一維的最大子序列和問題。轉換的關鍵就是,對於同一列,按照不同的方式求和(當然上下保證要連續的),然後將同一種求和方式排成一行,對這一行求取最大子序列和,遍歷完所有的求和方式,就OK了...

當然你也可以對於每一行來做這個,不過由於計算機儲存方式的關係,用行的話會增加快取的換入換出,減少快取的命中率。速度會變慢的。

好了,其實這道題沒有什麼新鮮的東西,唯一說一下的就是在記憶體的限制下,需要節約空間來做這個。

直接上程式碼吧。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_L 100

//(2*100^2)*4+100= 80000 = 80k
int a[MAX_L][MAX_L];
int sum[MAX_L][MAX_L];
int totalMax=-12800;  //儲存最終結果的,求和最小值不會超過-127*100

int findMax(int N){
  int rowP[MAX_L];  //臨時陣列
  int max,i,j;
  int *sumRowP,*rowA;  
  int row;
  
  for (row=0;row<N;row++){
    for (i=0;i<(N-row);i++){
      sumRowP=sum[i];
      rowA=a[row+i];
      for (j=0;j<N;j++){         //s(i,j)代表在輸入矩陣中,以第i行第j個元素為起始,垂直長度為row+1的列的和。
        sumRowP[j]+=rowA[j];
      }
      
      rowP[0]=sumRowP[0];   //問題轉化成,在這個行中,求最大子序列的問題
      for (j=1;j<N;j++){    //一維最大子序列和的問題
        if (rowP[j-1]<0){
          rowP[j]=sumRowP[j];
        }else{
          rowP[j]=rowP[j-1]+sumRowP[j];
        }
      }
      
      max=-12800;
      for (j=0;j<N;j++){
        if (rowP[j]>max)
          max=rowP[j];     //求出的max就是在垂直長度為row+1的所有矩形中,矩形內元素和的最大值
      }
      if (totalMax<max)
        totalMax=max;    //儲存最終結果的
    }
  }
}

int main(){
  int N,i,j;
  scanf("%d",&N);
  
  for (i=0;i<N;i++){
    for (j=0;j<N;j++){
      scanf("%d",&a[i][j]);
    }
  }

  memset(sum,0,MAX_L*MAX_L*sizeof(int));
  
  findMax(N);
  
  printf("%d",totalMax);
  return 0;
}

就這樣~加油!奮鬥