杭電OJ1003 C語言 詳解

2021-08-18 07:59:40 字數 2018 閱讀 4194

問題描述:problem-1003:max sum

本題用暴力解法時間複雜度高達o(n^3),會超時,因此找一種合適的方法來簡化問題;

最優子串行是個序列,那麼必然含有起始位置和終止位置,我們以每個a[i]作為研究物件,研究以i為終止位置的最優子串行,得出唯一確定的以a[i]為結尾的最優子串行,每個a[i]有乙個以他為結尾的最優子串行,再便利所有的最優子串行,找出最優子串行裡的最優為最終結果;

本題對最優的定義是和數最大(max sum);定義陣列a用來接收一組測試用例的所有數字;我們定義結構體陣列dp,dp[i]用來記錄以a[i]為結尾的最大子串行的資訊,dp[i].x用來記錄最大子串行起始位置,dp[i].val用來記錄最大子串行的和。

易知:dp[0].val=a[0],dp[0].x=0(以a[0]為結尾的序列只有乙個,即a[0]本身,因此dp[0]記錄的是序列(a[0])的和and位置);

通過dp[0]推導dp[1]、dp[2]、dp[3]、、、、、、dp[n-1];

推導思路:重點:dp[0]是以a[0]為結尾的最大子串行的乙個記錄,dp[1]必然含有a[1](因為dp[i]本身的含義是以a[i]為結尾的最大子串行,不含a[1]就不是以a[i]為結尾的序列了),dp[2]必然含有a[2]、、、、、、

首先,推dp[1],已知dp[0]是以a[0]為結尾的最大子串行,將dp[0]鏈結a[1],求dp[1],這個如何思考呢;

1    前面的序列和》0,a[1]>0,此時的情況記作++,此時序列無疑是越加越大的( dp[0]+a[1]>a[1]

),以a[1]為結尾的序列(dp[1])必然是前面的最大序列加上a[1];

2    前面的序列和》0,a[1]<0,此時為+-,此時序列無疑是越加越小的,但是仍然必須加上a[1],因為dp[1]規定了必須以a[1]為結尾,此時對於dp[1],因為 dp[0]+a[1]>a[1]

,所以dp[1]不取a[1]取dp[0]+a[1];

3    -+,此時dp[0]<0,既然我們要找乙個以a[1]為結尾的最大子串行,a[1]本身就比a[1]+dp[0]大( dp[0]+a[1]),那麼這個序列(dp[1])只取a[1]就夠了,不需要加上dp[0](加上前面的序列會越加越小,不是最大取法);

4    --,既然都是負數,那必然越加越小,即( dp[0]+a[1]),同上,取a[1]為dp[1]唯一值(此時可能有人會懵:倆都是負的,萬一dp[0]>a[1]呢,那按最大的取不應該取dp[0]而拋棄a[1]嗎,這就回到了重點:dp[1]必然含有a[1](因為dp[i]本身的含義是以a[i]為結尾的最大子串行),所以dp[1]只能取a[1]拋棄前面的dp[0]);

從以上總結出規律:dp[0]+a[1]>a[1]時,取dp[0]+a[1]為dp[1];dp[0]+a[1]<=a[1]時,取a[1]為dp[1];再從dp[0]、a[1]、dp[1]推廣到dp[i-1]、a[i]、dp[i],得到狀態轉移方程:dp[i]=max(dp[i-1]+a[i],a[i]);

根據方程求出所有的dp[i]後,再遍歷得到最大的子串行,時間複雜度為o(n);

當然也有更精簡的**,有空了再討論

#include "stdio.h"

struct dpdp[100000];

int main()

dp[0].val = a[0];

dp[0].x = 0;

for (int i = 1; i < n; i++)

else

} int s, e, max = -1001;

for (int i = 0; i < n; i++)

} printf("case %d:\n", q++);

printf("%d %d %d\n", max, s + 1, e + 1);

if (t)printf("\n");

} return 0;

}

杭電oj2000 C語言

problem description 輸入三個字元後,按各字元的ascii碼從小到大的順序輸出這三個字元。input 輸入資料有多組,每組佔一行,有三個字元組成,之間無空格。output 對於每組輸入資料,輸出一行,字元中間用乙個空格分開。sample input qwe asd zxcsampl...

杭電oj2001 C語言

題目 problem description 輸入兩點座標 x1,y1 x2,y2 計算並輸出兩點間的距離。input 輸入資料有多組,每組佔一行,由4個實數組成,分別表示x1,y1,x2,y2,資料之間用空格隔開。output 對於每組輸入資料,輸出一行,結果保留兩位小數。sample input...

杭電oj2040 2049 C語言

方便自己複習回顧 我在vc 編譯的所以用 int64定義超級大數 2040親和數 include intmain 求餘相加就行 for int n 1 nif sum1 m sum2 i else return0 2041超級樓梯 include stdio.h intmain for int i ...