最普通的版本
dp[i]=max{ dp[i-1]+dat[i] , dat[i] }
对于当前的数字dat[i], 有两种选择
A.原子串增长,dp[i]=dp[i-1]+dat[i]
~~~~~前提是dat[i]<=dp[i-1]+dat[i]
B.原子串结束,以dat[i]为起点开始新子串。
~~~~~前提是dat[i]>dp[i-1]+dat[i]
注:以原子串的长度来划分有三种情况。
1.增长 对应上文选择中的A
2.不变 对应B,这种长度不变的情况是不符合题意的,因为题目要求子串连续,也就是说面对新的数字dat[i] 要么同化(dp[i]=dp[i-1]+dat[i]),要么异化(dp[i]=dat[i])
不能忽略~比如 dat[1]=10,dat[2]=20,dat[3]=-100,那么dp[1]=10 dp[2]=30 dp[3]=-70 ,答案max=dp[2]=30......
3.减短,,,,,,,算了吧
#include<iostream>
using namespace std;
int main()
{
int t,T,i,j,N,now,max,temp,begin,end,x;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
scanf("%d%d",&N,&temp);
now=max=temp;
begin=end=x=1;
// printf("i1 temp%d now%d x%d max%d begin%d end%d \n",temp,now,x,max,begin,end);
for(i=2;i<=N;i++)
{
scanf("%d",&temp);
if(temp>now+temp) now=temp,x=i; //即if(now<0) now=temp,x=i;
else now+=temp;
if(max<now)
{
begin=x;
end=i;
max=now;
}
// printf("i%d temp%d now%d x%d max%d begin%d end%d \n",i,temp,now,x,max,begin,end);
}
printf("Case %d:\n%d %d %d\n",t,max,begin,end);
if(t!=T) printf("\n");
}
return 0;
}
练习
#include<stdio.h>
int main()
{
int i,n,temp,now,max,begin,x,end,flag,flagBegin,flagEnd;
while(scanf("%d",&n),n)
{
flag=1;
scanf("%d",&temp); flagBegin=temp;
if(temp>=0) flag=0;
x=begin=end=now=max=temp;
for(i=2;i<=n;i++)
{
scanf("%d",&temp); if(temp>=0) flag=0;
if(temp>now+temp) x=now=temp;
else now+=temp;
if(max<now) max=now,begin=x,end=temp;
}
flagEnd=temp;
if(flag) printf("%d %d %d\n",0,flagBegin,flagEnd);
else printf("%d %d %d\n",max,begin,end);
}
return 0;
}
M个子串最大和
dp[i][j] = max(dp[i][j-1] , dp[i-1][t] )+ dat[j] (i<=k<j)
感觉蛮难理解的, 参考
#include<iostream>
#include<algorithm>
using namespace std;
int dpmax[1000005],dp[1000005],dat[1000005];
int main()
{
int i,j,m,n,MAX;
while(scanf("%d%d",&m,&n)!=EOF)
{
for(i=1;i<=n;i++) scanf("%d",&dat[i]);
memset(dpmax,0,sizeof(dpmax[0])*n+4);
for(i=1;i<=m;i++)
{
MAX=-99999999;
for(j=i;j<=n;j++)
{
dp[j]=max(dpmax[j-1],dp[j-1])+dat[j];
dpmax[j-1]=MAX;
if(MAX<dp[j]) MAX=dp[j];
}
dp[j-1]=MAX;//也可以写成dp[j-1]=max(dpmax[j-2],dp[j-1]); 不理解
}
printf("%d\n",dp[n]);
}
return 0;
}
递增子串
#include<stdio.h>
#include<string.h>
int num[1001],dp[1001];
int main()
{
int m,n,i,j,sum;
num[0]=0;
while(scanf("%d",&n),n)
{
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
for(j=0;j<i;j++)
{
if(num[j]<num[i]&&dp[i]<dp[j]+num[i])
dp[i]=dp[j]+num[i];
}
}
//for(i=1;i<=n;i++)
// printf("%d ",dp[i]);printf("\n");
for(dp[n+1]=j=0;j<=n;j++)
if(dp[n+1]<dp[j]) dp[n+1]=dp[j];
printf("%d\n",dp[n+1]);
}
return 0;
}
pku2533最长递增子序列
注意初始化
#include<stdio.h>
#include<string.h>
int dp[1001],n[1001];
int main()
{
int i,j,N;
n[0]=0;
while(scanf("%d",&N)!=EOF)
{
for(i=1;i<=N;i++)
{
scanf("%d",&n[i]);
dp[i]=1;
for(j=1;j<i;j++)
{
if(n[j]<n[i]&&dp[i]<dp[j]+1)
dp[i]=dp[j]+1;
}
// for(j=0;j<=N;j++)
// printf("%d ",dp[j]);printf("\n");
}
for(dp[0]=0,i=1;i<=N;i++)
if(dp[0]<dp[i]) dp[0]=dp[i];
printf("%d\n",dp[0]);
}
return 0;
}
最大子矩阵和
计算出dp[i][j],表示第i行前j个数的和。
前两层循环遍历i,j所有可能的组合
得到的每一组(i,j)表示矩阵的第i~j列,相当于hdu1003的一组数据
#include<stdio.h>
#include<string.h>
int dp[105][105];
int main()
{
int i,j,k,N,sum,max;
while(scanf("%d",&N)!=EOF)
{
memset(dp,0,sizeof(dp));
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
{
scanf("%d",&sum);
dp[i][j]+=dp[i][j-1]+sum;
}
max=-99999999;
for(i=1;i<=N;i++)
{
for(j=i;j<=N;j++)
{
sum=0;
for(k=1;k<=N;k++)
{
if(sum<0) sum=dp[k][j]-dp[k][i-1];
else sum+=dp[k][j]-dp[k][i-1];
if(max<sum) max=sum;
}
}
}
printf("%d\n",max);
}
return 0;
}
/*
4
-1 -1 -1 -1
-1 -1 -1 -1
-1 -1 -1 -1
-1 -1 -1 -1
*/
穷举
#include<iostream>
using namespace std;
int sum[1005][1005];
int main()
{
int T,m,n,x,y,i,j,k,max,num;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&m,&n,&x,&y);
memset(sum,0,sizeof(sum));
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&max);
sum[i][j]=sum[i][j-1]+max;
}
}
max=0;
for(i=1;i<=m-x+1;i++)
{
for(j=1;j<=n-y+1;j++)
{
num=0;
for(k=0;k<y;k++)
num+=sum[i+k][j+y-1]-sum[i+k][j-1];
if(max<num) max=num;
}
}
printf("%d\n",max);
}
return 0;
}