poj1050最大欄位和及其衍生
每天做poj都會感覺到自己的收穫,今天做的是poj1050,以前沒接觸這些演算法類的東西,也就在資料結構課上水過兩把,所以每天接觸到這些新的東西覺得挺有意思,也確實感覺自己收穫了不少。
poj1050是一個欄位和的題,什麼是欄位和以及他的具體實現我是在這篇部落格上學到的,點選開啟連結
對照著他的思路,我自己用Java實現了一下加深理解。欄位和簡單地說就是給你一行數字,有正有負,我們要做的就是,計算下標i到下標J之間的數字(這之間是連續的下標),是這些數字的和是最大的,我們需要求的就是這個最大值。
根據上面部落格的連結,對於欄位和的實現大約有三種方法。
1、窮舉法
顧名思義,就是依次遍歷第一個下標到最後一個下標,最直接的思路是設定三重迴圈,最外層的大迴圈是起始座標的位置,第二層迴圈是再確定起始座標的基礎上,確定的終止座標的位置,第三重迴圈就是變數i在起始座標和終止座標之間取值,設定一個max和temp,把每一個變數指定的座標對應的元素加到temp上,再和max比較大小,如果比max大的話就把值賦給max,此時如果需要記錄起始座標和終點座標,就要額外設定兩個變數用來記錄最大值時對應的i和J。
對於上面的這種方法,細想一下的話我們會發現有些步驟是重複的,其實只用兩重迴圈就能做到。已知起始位置,終止位置每向後移一次,就把那個位置對應的元素加到temp上,再和max比較,這樣就可以減少時間複雜度。
2、分治法
看完原部落格的這個方法之後,理解倒是挺好理解,就是要分情況進行實現,而且對於起始位置和終點位置在不同的半邊的那種情況處理起來比較麻煩,我以後應該不會優先考慮這個演算法。
3、動態規劃法(dp)
又見動態規劃,動態規劃的思想放在這個題目裡面,怎麼說呢,因為實現的步驟過於簡單,主要是想想清楚這之間的邏輯關係,也就是說為什麼這樣可以達到目的,還是兩個用來記錄和的變數max和temp,temp還是記錄臨時和的變數。當變數i加1指向下一個元素a[i]的時候,判斷temp是不是>0,大於0,說明是有必要和a[i]進行相加的,因為如果temp<0的話,無論a[i]的值是正或者負,如果temp和a[i]相加都必然會使和比a[i]要小,因此,當temp<0時,我們將a[i]的值賦給temp作為新的temp值。而在temp>0時,如果a[i]>0,則會使新的temp更大,與max比較如果大於max則對max重新賦值,若否則不作處理,同樣,就算a[i]是小於0,就更不會對max的值有影響。這樣我們就可以找到這個欄位裡的最大的數字和。
放在1050這道題裡,就算是一個二維的欄位求和,只需要在一維的基礎上,遍歷每一行,將其與下面的一行,兩行.....直到最後一行加到一起,組成了一個新的一維欄位,所以我們實際是對這個新的欄位進行處理。
程式碼詳情如下:
package cn.itcast_test; import java.util.Scanner; public class Max{ public static void main(String args[]){ Scanner scan=new Scanner(System.in); int n=scan.nextInt(); int [][]arr=new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ arr[i][j]=scan.nextInt(); } } int max=-1000; //挨個計算每一行的最大值 for(int i=0;i<n;i++){ int temp=0; for(int j=0;j<n;j++){ if(temp>0){ temp+=arr[i][j]; if(temp>max){ max=temp; } }else{ temp=arr[i][j]; } } } //依次將每一行與下面的一行、兩行、、、、和所有行慢慢累加到一起,算上一行之後進行最大值查詢 for(int i=0;i<n-1;i++){ for(int j=i+1;j<n;j++){ int temp=0; for(int k=0;k<n;k++){ arr[i][k]+=arr[j][k]; if(temp>0){ temp+=arr[i][k]; if(temp>max){ max=temp; } }else{ temp=arr[i][k]; } } } } System.out.println(max); } }