前些天學車...真是相當累啊,比上課累,現在終於可以休息了...
重新看《算法導論》,不過這下可得認真看了,9個月不到就得去找工作了,與我同樣的大三黨們一樣加油咯...
《算法導論》中引入這個問題是通過股票的購買與出售,將前一天的當天的股票差價重新表示出來,即轉爲了一個最大子數組的問題,具體內容我不多說,轉的內容是:
13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7
找到這連續的16個數裏面的連續和最大的子數組;
書中練習部分說用設計非遞歸的,線性時間的算法,我就YY爲動態規劃處理了;
從數組的左邊界開始,從左至右處理,記錄到目前爲止已經處理過的最大子數組。若已知A[1..j]的最大子數組,基於如下性質將解擴展爲A[1...j+1]的最大子數組:A[1...j+1]的最大子數組要麼是A[1...j]的最大子數組,要麼是某個子數組A[i...j+1](1<=i<=j+1)。在已知A[1...j]的最大子數組的情況下,可以在線性時間內找出形如A[i...j+1]的最大子數組;
思想上述都將出來了,只要將關鍵點寫出即可:
如果前面若干和<0,則其對後面子數組相加無幫助,此時重置dp爲array[i],並且記錄的起始位置重新標記;
if(dp[i - 1] <= 0) //前面的<0,直接丟棄
{
dp[i] = array[i];
temp = i; //記錄起始爲止
}
否則,繼續往後延伸;
dp[i] = array[i] + dp[i - 1]; //往後求和
最後判斷最大子數組值就行,同時標記起始與結束位置:
if(dp[i] > MaxSumSub) //找到到i爲止的最大子數組
{
MaxSumSub = dp[i]; //最大...
start = temp; //標記起始
end = i; //標記此時的結束位置
}
代碼:
#include <iostream>
using namespace std;
int FindMaxSubarray(int array[], int length)
{
int start = 0, end = 0; //記錄最大子數組的起始位置(在數組中的下標)
int MaxSumSub; //最大子數組的值
int* dp = new int[length]; //動態規劃記錄
dp[0] = array[0]; //初始爲第一個數
MaxSumSub = dp[0]; //最大值初始爲第一個數
int temp = 0; //
for(int i = 1; i < length; i++)
{
if(dp[i - 1] <= 0) //前面的<0,直接丟棄
{
dp[i] = array[i];
temp = i; //記錄起始爲止
}
else
dp[i] = array[i] + dp[i - 1]; //往後求和
if(dp[i] > MaxSumSub) //找到到i爲止的最大子數組
{
MaxSumSub = dp[i]; //最大...
start = temp; //標記起始
end = i; //標記此時的結束位置
}
}
cout<<"最大子序列的下標:"<<start<<"->"<<end<<endl;
return MaxSumSub;
}
int main()
{
int a[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
//int a[] = {23, 4};
int length = sizeof(a) / sizeof(int);
cout<<FindMaxSubarray(a, length);
return 0;
}
最大子序列即爲{18, 20, -7, 12};
上述dp即爲動態記錄尋找最大子數組的過程,大家也可以進行輸出看一下;
歡迎大家指點,o(∩_∩)o