最大連續子串
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;elsenow+=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;elsenow+=temp;if(max<now)max=now,begin=x,end=temp;}flagEnd=temp;if(flag)printf("%d %d %d\n",0,flagBegin,flagEnd);elseprintf("%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個數的和。
20~32行 dp
前兩層迴圈遍曆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;}