关于最长大子段和问题,如果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,。另外继续肝,重在平时,每天两道题。