hdu1003
最普通的版本
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; }
练习
hdu1231
#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; }
hdu1024
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; }
递增子串
hdu1087
#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; }
最大子矩阵和
hdu1081
11~17行预处理 计算出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 */
hdu1559
穷举
#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; }