[DP]#hdu1003#hdu1087#hdu1159
hdu1003最大字段和
hdu1087 最长不降子序列(LIS)
hdu1159 最长公共子序列(LCS)
1003
1.全是负数的数据。(寻找最大和的时候,初始值要选择最小的int,而不是0,否则会有错误)
2.都满足条件的时候只输出第一种情况
#include<iostream> #include<cstdio> using namespace std; const int maxnum=100000+1; #define rep(i,n,m) for(int i=(n);i<=(m);++i) #define re1(i,n) rep(i,1,n) int a[maxnum]; int n; int main(){ int tcase,tnum=0; scanf("%d",&tcase); while(tcase--){ scanf("%d",&n); re1(u,n){ scanf("%d",&a[u]); } int sum=2147483647+1,from=1,to=0,j=1,b=-1;//最小的int(+1就溢出为最小int) rep(i,1,n){ if(b<0){ b=a[i]; j=i;//j记录了每一段的开始节点。 }else{ b=b+a[i]; } if(b>sum){ sum=b; from=j; to=i; } } printf("Case %d:\n%d %d %d\n",++tnum,sum,from,to); if(tcase) printf("\n"); } }
1159
1.注意dp数组从1,1开始处理,退化情况就能统一处理,所以对应字符串用i-1,j-1
2.题目没有要求输出子序列,不过我写了一个递归函数。
3.这个是基本的题目,有空我再讲解吧。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rep(i,n,m) for(int i=(n);i<=(m);++i) #define re1(i,n) rep(i,1,n) #define re0(i,n) rep(i,0,n) using namespace std; const int maxnum=10000+1; char a[maxnum],b[maxnum]; int dp[maxnum][maxnum]; int way[maxnum][maxnum]; template<class T> void show(T a[][maxnum],int n,int m){ re0(i,n){ re0(j,m){ cout<<a[i][j]<<' '; } cout<<endl; } } void makeSub(int i,int j){ if(i==0 && j==0) return; if(way[i][j]==1){ makeSub(i-1,j-1); cout<<b[j-1]; }else if(way[i][j]==2){ makeSub(i,j-1); }else makeSub(i-1,j); } int main(){ while(~scanf("%s%s",a,b)){ int la=strlen(a); int lb=strlen(b); re1(i,la)re1(j,lb){ dp[i][j]=0; way[i][j]=0; } re1(i,la)re1(j,lb){ if(a[i-1]==b[j-1]){ dp[i][j]=dp[i-1][j-1]+1; way[i][j]=1;//<\ // cout<<a[i-1]<<' '<<b[i-1]<<endl; } else{ if(dp[i][j-1]>=dp[i-1][j]){ dp[i][j]=dp[i][j-1]; way[i][j]=2;//<- }else{ dp[i][j]=dp[i-1][j]; way[i][j]=3;//<| } } } //show(dp,la,lb); printf("%d\n",dp[la][lb]); // makeSub(la,lb); // cout<<endl; } }
1087
1.动态规划的思想,dp[i]为A[i]为最后元素的最长上升子序列的长度,所以dp[i]=max(dp[j])+1,这里的j为小于(不等于)i大于等于1(从1开始),并且j为满足A[j]<A[i]的也就是说只有满足了A[i]比A[j]大,并且还要是之前最长的上升子序列,然后+1就是当前的i。能说的就这样了,这道题,本来dp应该存放长度,但是为了简单,我省去了长度,直接放和了。
#include<iostream> #include<cstdio> #define rep(i,n,m) for(int i=(n);i<=(m);++i) #define re1(i,n) rep(i,1,n) #define re0(i,n) rep(i,0,n) const int maxnum=1000+1; const int lowestint=-2147483647; int a[maxnum],dp[maxnum]; using namespace std; template<class T> void show(T *a,int n,int m){ rep(u,n,m){ cout<<a[u]<<' '; } cout<<endl; } int main(){ int n; while(scanf("%d",&n)){ if(n==0) break; re1(u,n){ scanf("%d",&a[u]); dp[u]=a[u]; } dp[0]=0; re1(i,n){ int bigcount=lowestint; int big=0; re1(j,i-1){ if(a[j]<a[i]&&bigcount<dp[j]){ bigcount=dp[j]; big=j; } } dp[i]=dp[big]+a[i]; } //show(dp,0,n); int big=0,bigcount=lowestint; re1(u,n) if(bigcount<dp[u]){ big=u; bigcount=dp[u]; } printf("%d\n",bigcount); } }