最大子序列、最长递增公共子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
http://www.cnblogs.com/zhangchaoyang/articles/2012070.html
最大子序列
最大子序列是要找出由数组成的一维数组中和最大的连续子序列。比如{5,-3,4,2}的最大子序列就是 {5,-3,4,2},它的和是8,达到最大;而 {5,-6,4,2}的最大子序列是{4,2},它的和是6。你已经看出来了,找最大子序列的方法很简单,只要前i项的和还没有小于0那么子序列就一直向后扩展,否则丢弃之前的子序列开始新的子序列,同时我们要记下各个子序列的和,最后找到和最大的子序列。
http://acm.hdu.edu.cn/showproblem.php?pid=1003
//模板,思想。 #include<stdio.h> #define Min -999999 int main() { int data[100000],start,end,t,i; int m; scanf("%d",&m); for(t=1;t<=m;t++) { int n; scanf("%d",&n); for ( i=1; i<=n;i++) scanf("%d",&data[i]); int max = Min; int k=1; int sum = 0; for (i=1; i<=n; i++) { sum = sum + data[i]; //printf("sum=%d\n",sum); if (sum > max) { // printf("max=%d\n",max); max = sum; start=k; end=i; } if(sum<0) { sum=0; k=i+1; } } printf("Case %d:\n",t); printf("%d %d %d\n",max,start,end); if(t!=m) printf("\n"); } return 0; }
最长公共递增序列
http://acm.hdu.edu.cn/showproblem.php?pid=1423
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a[600],b[600]; int GCIS(int l1, int l2) { int DP[600]; int i,j,k,max; memset(DP,0,sizeof(DP)); for (i=1; i<=l1; i++) { k=0; for (j=1; j<=l2; j++) { if (b[j-1]<a[i-1] && DP[j]>DP[k]) k=j; if (b[j-1]==a[i-1] && DP[k]+1>DP[j]) DP[j]=DP[k]+1; } } for(max=0,i=1; i<=l2; i++) if (DP[i]>DP[max]) max=i; return DP[max]; } int main() { int T,n,m,i; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=0; i<n; i++) scanf("%d",&a[i]); scanf("%d",&m); for(i=0; i<m; i++) scanf("%d",&b[i]); printf("%d\n",GCIS(n,m)); if(T) printf("\n"); } return 0; }
最长公共递增序列记录路径:zoj
http://blog.csdn.net/cclsoft/article/details/4537299
最长公共子序列、子序列问题。
http://acm.hdu.edu.cn/showproblem.php?pid=1159
若str1[i]=str2[j] dp[i][j]=dp[i-1][j-1]+1
若str1[i]!=str2[j] dp[i][j]=max(dp[i-1][j],dp[i][j-1])
#include<iostream> #include<cstdio> #include<cstring> using namespace std; char str1[1005],str2[1005]; int dp[1005][1005]; int main() { int i,j; while(~scanf("%s%s",str1,str2)) { memset(dp,0,sizeof(dp)); int l1=strlen(str1); int l2=strlen(str2); if(str1[0]==str2[0]) dp[0][0]=1; else dp[0][0]=0; for(i=1;i<l1;i++) { if(str1[i]==str2[0]) dp[i][0]=1; else dp[i][0]=dp[i-1][0]; } for(i=1;i<l2;i++) { if(str1[0]==str2[i]) dp[0][i]=1; else dp[0][i]=dp[0][i-1]; } for(i=1;i<l1;i++) { for(j=1;j<l2;j++) { if(str1[i]==str2[j]) dp[i][j]=dp[i-1][j-1]+1; else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); //printf("dp=%d\n",dp[i][j]); } } printf("%d\n",dp[l1-1][l2-1]); } return 0; }
最长递增子序列:
http://poj.org/problem?id=2533
这是我觉得简单一点的模板。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int a[10000]; int los(int l) { int dp[10000]; int i,j,k,max; memset(dp,0,sizeof(dp)); for(i=1;i<l;i++) for(j=0;j<i;j++) if(a[j]<a[i]&&dp[i]<=dp[j]) dp[i]=dp[j]+1; for(max=0,i=1; i<=l; i++) if (dp[i]>dp[max]) max=i; return dp[max]; }
但是我自己做的:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int a[10000]; int los(int l) { int dp[10000]; int i,j,k,max; memset(dp,0,sizeof(dp)); for(i=1;i<=l;i++) { k=0; for(j=1;j<=i;j++) { if(i==j) continue; if(a[i-1]>a[j-1]) k=j; if(dp[k]+1>dp[i]&&k!=0) dp[i]=dp[k]+1; } } for(max=0,i=1; i<=l; i++) if (dp[i]>dp[max]) max=i; return dp[max]; } int main() { int i,n; while(~scanf("%d",&n)) { for(i=0;i<n;i++) scanf("%d",&a[i]); printf("%d\n",los(n)+1); } return 0; }
但是有时最长递增子序列的时间缩短。
http://poj.org/problem?id=3903
题意:依旧是一道LIS的裸题
思路:要注意数据比较多,要用二分的优化法,原本是与POJ2533一样的题,但是用2533的代码只改下数组大小是过不了的,WA了几次,后来发现二分函数需要改进,于是改成了下面的方式,而且这个二分函数用在2533也是可以的
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int a[100005],c[100005]; int n; int find(int size,int k) { int l,r,mid; l=1;r=size; while(l<=r) { mid=(l+r)/2; if(k>c[mid]) l=mid+1; else r=mid-1; } return l; } int LIS() { int i; int cnt=1; c[++cnt]=a[1]; for(i=2;i<=n;i++) { if(a[i]>c[cnt]) c[++cnt]=a[i]; else { int k=find(cnt,a[i]); c[k]=a[i]; } } return cnt-1; } int main() { int i; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%d",&a[i]); printf("%d\n",LIS()); } }
接下来就是这个网站: