這是一道動態規劃的題目,剛學了一點動態規劃還不太熟悉,這一道題研究了很久才做出來
題目大意:
輸入n個數字,其中的數字可以按排列順序相加,找出相加值最大的子序列,輸出該最大值和起點終點
思路:
該題使用dp來做,整體的思路根據 max{dp[i]+sum, dp[i]} 來判斷, 數字相加不是一遇到負數就停止相加,而是直到發現之前相加的結果成了負數爲止。
我們可以設置變量ans存儲最終的結果、變量temp暫時存儲目前相加得到的結果,同時要記錄是從第幾個數開始相加,到第幾個數停止,每相加一次後temp都會改變,如果temp大於ans就更新結果。
這是一個邊記錄最大值邊嘗試的過程,每一次temp大於ans時更新最大值。當dp[i]是一個正數時相加後temp肯定會更大所以就毫不猶豫繼續往後相加;當dp[i]是一個負數時相加後temp肯定會變小,但只要temp仍然不是一個負數,即是暫時變小了一些但通過之後的相加還是有可能變得更大,所以我們要給dp[i]<0一個機會,j繼續往後相加,希望讓之後的數來彌補減去的這部分,就算之後不斷相加temp還是沒有減小之前大也沒關係,因爲在ans中已經存放了最大的情況。如果temp一直與負數相加最後可能會變成一個負數,此時下一個數就算是一億,相加後temp會變成一個很大的數,但仍然比一億小,負數的部分對這個一億來說卻是一個累贅,遠不如直接捨棄之前的所有數,從一億重新開始向後相加。
完整代碼如下:
#include<stdio.h>
int main() {
int t, n ;
int data[100005] ;
int temp, ans, first, last, x, y ;
scanf("%d", &t) ;
for(int i=1; i<=t; i++) {
scanf("%d", &n) ;
for(int j=0; j<n; j++)
scanf("%d", &data[j]) ;
x = y = first = last = temp = 0 ;
ans = -1000000 ;
for(int j=0; j<n; j++) {
if(temp+data[j] >= data[j]) { //只有temp爲負數時再加多大的數都不如直接從新的數開始
temp += data[j] ;
last = j ;
}
else {
temp = data[j] ; //從新的點開始計
first = last = j ;
}
if(temp > ans) { //更新結果
ans = temp ;
x = first ; //開始
y = last ; //停止
}
}
printf("Case %d:\n", i) ;
printf("%d %d %d\n", ans, x+1, y+1) ; //因爲從0開始所以要加一
if(i < t)
printf("\n") ;
}
return 0 ;
}
總結:
dp不好搞。。。。