關於最長大子段和問題,如果dp[i]是以a[i]爲結尾的前i項的最大子段和,那麼只需要考慮dp[i-1]的具體情況,如果大於0,則dp[i]=dp[i-1]+a[i],如果小於0,則最大子段和的起始位置更新,dp[i]=a[i];因爲如果dp[i-1]小於0,子段和趨於減小,其與a[i]相加後的和比a[i]小。
這一直是困擾我的地方,想了好久,就是感覺不通透,每天都看很多關於最大子段和的題目解析,都是一句話帶過——易知。當繞過這個彎兒來,一切都明朗了。
以下是我自己寫的最大子段和的代碼實現,其中標註了起點和終點,其實還可以改成起始元素和終止元素本身。
#include <iostream>
#include <cstring>
using namespace std;
int a[10001],dp[10001];
int main()
{
int n;
cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i];
int sum = 0,s=1,e = 1;
dp[1] = max(a[1],0);
for(int i = 2;i<=n;i++)
{
if(dp[i-1]<0)
{
dp[i] = a[i];
s = i;
}
else
{
dp[i] = dp[i-1]+a[i];
}
}
for(int i = 1;i<=n;i++)
if(sum<dp[i])
{
sum=dp[i];
e=i;
}
cout<<sum<<" "<<s<<" "<<e<<endl;
return 0;
}
今天班裏去春遊,很累,但是還是勉強看完了0-1揹包問題,基本原理已經搞懂,記錄每次放入揹包的價值總和,和揹包當前的價值比較,加和最大值。其實算法圖解中還有一個很好的解析,圖文結合,原理明瞭。 粗略的寫了一下代碼。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int c[10001];int v[10001];
int f[10001];
int main()
{
int t,n,x;//n爲數量,x爲容積
cin>>t;
while(t--)
{
cin>>n>>x;
memset(f,0,sizeof(f));
for(int i = 0;i<n;i++)
cin>>v[i];
for(int i = 0;i<n;i++)
cin>>c[i];
for(int i = 0;i<n;i++)
for(int j = x;j>=c[i];j--)
f[j] = max(f[j-c[i]]+v[i],f[j]);
cout<<f[x]<<endl;
}
return 0;
}
開始感覺做dp的樂趣所在,就那麼幾個問題,翻來覆去的變,但原理都一樣,套用上基本代碼,稍作修改,好多題都可以AC,。另外繼續肝,重在平時,每天兩道題。