Longest Ordered Subsequence HDU2533
求最长递增子序列的模板:
Slyar:属于简单的经典的DP,求最长上升子序列(LIS)。先研究了O(n^2)的思路。
令A[i]表示输入第i个元素,D[i]表示从A[1]到A[i]中以A[i]结尾的最长子序列长度。对于任意的0 < j <= i-1,如果A(j) < A(i),则A(i)可以接在A(j)后面形成一个以A(i)结尾的新的最长上升子序列。对于所有的 0 < j <= i-1,我们需要找出其中的最大值。
DP状态转移方程:
D[i] = max{1, D[j] + 1} (j = 1, 2, 3, ..., i-1 且 A[j] < A[i])
解释一下这个方程,i, j在范围内:
如果 A[j] < A[i] ,则D[i] = D[j] + 1
如果 A[j] >= A[i] ,则D[i] = 1
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 int main() 6 { 7 int n,i,j,MAX,dp[2005],a[2005]; 8 while(scanf("%d",&n)!=EOF) 9 { 10 MAX=0; 11 for(i=0;i<n;i++) 12 scanf("%d",&a[i]); 13 for(i=0;i<n;i++) 14 { 15 dp[i]=1; 16 for(j=0;j<i;j++) 17 if(a[i]>a[j]&&dp[i]<dp[j]+1) 18 dp[i]=dp[j]+1; 19 if(dp[i]>MAX) 20 MAX=dp[i]; 21 } 22 printf("%d ",MAX); 23 } 24 return 0; 25 }
还有可以用二分法找最长子序列,但具体是多少求不出。
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 int b[1005]; 7 int main() 8 { 9 int n,a,len,left,right,mid,i; 10 while(scanf("%d",&n)!=EOF) 11 { 12 len=0; 13 memset(b,0,sizeof(b)); 14 b[0]=-1; 15 for(i=1;i<=n;i++) 16 { 17 scanf("%d",&a); 18 if(a>b[len]) 19 { 20 len++; 21 b[len]=a; 22 } 23 else if(a<b[len]) 24 { 25 left=0; 26 right=len; 27 while(right-left>1) 28 { 29 mid=(left+right)/2; 30 if(a<=b[mid]) 31 right=mid; 32 else 33 left=mid; 34 } 35 b[right]=a; 36 } 37 } 38 printf("%d ",len); 39 } 40 }
Common Subsequence HDU 1159
给出求最长公共子序列的模板:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 char a[1005],b[1005]; 7 int dp[1005][1005]; 8 int main() 9 { 10 int n,m,i,j; 11 while(scanf("%s%s",a+1,b+1)!=EOF) 12 { 13 n=strlen(a+1); 14 m=strlen(b+1); 15 memset(dp,0,sizeof(dp)); 16 for(i=1;i<=n;i++) 17 for(j=1;j<=m;j++) 18 { 19 if(a[i]==b[j]) 20 dp[i][j]=dp[i-1][j-1]+1; 21 else if(dp[i][j-1]>dp[i-1][j]) 22 dp[i][j]=dp[i][j-1]; 23 else 24 dp[i][j]=dp[i-1][j]; 25 } 26 printf("%d ",dp[n][m]); 27 } 28 return 0; 29 }
Greatest Common Increasing Subsequence HDU 1423
第三个模板:(俩者的综合)
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int a[1005],b[1005],f[1005]; 7 int main() 8 { 9 int t,m,n,i,j,max1; 10 scanf("%d",&t); 11 while(t--) 12 { 13 scanf("%d",&m); 14 for(i=0;i<m;i++) 15 scanf("%d",&a[i]); 16 scanf("%d",&n); 17 for(i=0;i<n;i++) 18 scanf("%d",&b[i]); 19 memset(f,0,sizeof(f)); 20 for(i=0;i<m;i++) 21 { 22 max1=0; 23 for(j=0;j<n;j++) 24 { 25 if(a[i]>b[j]&&max1<f[j]) 26 max1=f[j]; 27 if(a[i]==b[j]) 28 f[j]=max1+1; 29 } 30 31 } 32 max1=0; 33 for(i=0;i<n;i++) 34 if(f[i]>max1) 35 max1=f[i]; 36 printf("%d ",max1); 37 if(t) printf(" "); 38 } 39 return 0; 40 }
回文字符:就是把它调换,求最长公共序列。
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 #include<string.h> 5 using namespace std; 6 char a[5005],b[5005]; 7 int c1[2][5005];//注意压缩路径!!减小内存(用到滚动数组):常用于DP中,因一个式子只由前面俩个或三个推出来的,所以可以压缩求出结果(但是此方法只能求出最后结果,中间的任何情况被来回的取模给淹没了!!!) 8 int main() 9 { 10 int n,i,j; 11 while(scanf("%d",&n)!=EOF) 12 { 13 scanf("%s",a+1); 14 n=strlen(a+1); 15 for(i=1;i<=n;i++) 16 b[i]=a[n+1-i]; 17 memset(c1,0,sizeof(c1)); 18 for(i=1;i<=n;i++) 19 for(j=1;j<=n;j++) 20 { 21 if(a[i]==b[j]) 22 c1[i%2][j]=c1[(i-1)%2][j-1]+1; 23 else if(c1[i%2][j-1]>c1[(i-1)%2][j]) 24 c1[i%2][j]=c1[i%2][j-1]; 25 else 26 c1[i%2][j]=c1[(i-1)%2][j]; 27 } 28 printf("%d ",n-c1[n%2][n]); 29 } 30 return 0; 31 }
魔法串 HDU 4545
一个求最长公共子序列的变行:
题意:多了一个条件:第二个可以字符变换。
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdio.h> 5 using namespace std; 6 char a[1005],b[1005],a1[2],b1[2]; 7 bool s[1005][1005];//竟然可以这么用(布尔函数) 8 int dp[1005][1005]; 9 int main() 10 { 11 int d=0,t,x,n,m,i,j; 12 scanf("%d",&t); 13 while(t--) 14 { 15 scanf("%s %s",a+1,b+1); 16 n=strlen(a+1); 17 m=strlen(b+1); 18 memset(dp,0,sizeof(dp)); 19 memset(s,0,sizeof(s)); 20 scanf("%d",&x); 21 while(x--) 22 { 23 scanf("%s %s",a1,b1); 24 s[a1[0]][b1[0]]=1;//这里就简化了很多步骤!! 25 } 26 for(i=1;i<=m;i++) 27 for(j=1;j<=n;j++) 28 { 29 if(b[i]==a[j]||s[b[i]][a[j]]) 30 dp[i][j]=dp[i-1][j-1]+1; 31 else if(dp[i][j-1]>dp[i-1][j]) 32 dp[i][j]=dp[i][j-1]; 33 else 34 dp[i][j]=dp[i-1][j]; 35 36 } 37 if(dp[m][n]==n) 38 printf("Case #%d: happy ",++d); 39 else 40 printf("Case #%d: unhappy ",++d); 41 } 42 return 0; 43 }
这个反映了求这类问题的核心思路:(最长递减子序列和最长递增序列在这个问题可以互换)
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 int main() 6 { 7 int n,i,j,MAX,dp[2005],a[2005]; 8 while(scanf("%d",&n)!=EOF) 9 { 10 MAX=0; 11 for(i=0;i<n;i++) 12 scanf("%d",&a[i]); 13 for(i=0;i<n;i++) 14 { 15 dp[i]=1; 16 for(j=0;j<i;j++) 17 { 18 if(a[i]>a[j]&&dp[i]<dp[j]+1) 19 dp[i]=dp[j]+1; 20 } 21 if(dp[i]>MAX) 22 MAX=dp[i]; 23 } 24 printf("%d ",MAX); 25 } 26 return 0; 27 }
貌似这题目太水了!!你求出最长递增子序列的长度和最长不递减子序列的长度都可以AC掉!!!
1 #include<cstdio> 2 3 int main() 4 { 5 int n,i,j,num,h[1000],max[1000]; 6 while(~scanf("%d",&n)) 7 { 8 num=0; 9 for(i=0;i<n;++i) 10 { 11 scanf("%d",&h[i]); 12 max[i]=1; 13 } 14 for(i=1;i<n;++i) 15 for(j=0;j<i;++j) 16 { 17 if(h[j]<=h[i]&&max[j]+1>max[i]) 18 max[i]=max[j]+1; 19 if(num<max[i]) 20 num=max[i]; 21 } 22 printf("%d ",num); 23 } 24 return 0; 25 }
Nested Dolls HDU 1677
貌似这个题目和上面的类型一样,更加深刻结题思路。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 struct line 7 { 8 int x; 9 int y; 10 }a[20005]; 11 bool comp1(line a,line b) 12 { 13 if(a.x!=b.x) return a.x>b.x; 14 return a.y<b.y; 15 } 16 int b[20005]; 17 int main() 18 { 19 int t,i,left,right,mid,len,n; 20 scanf("%d",&t); 21 while(t--) 22 { 23 scanf("%d",&n); 24 for(i=0;i<n;i++) 25 scanf("%d%d",&a[i].x,&a[i].y); 26 sort(a,a+n,comp1); 27 len=0;b[0]=-1; 28 for(i=0;i<n;i++) 29 { 30 if(a[i].y>=b[len]) 31 { 32 len++; 33 b[len]=a[i].y; 34 } 35 else 36 { 37 left=0; 38 right=len; 39 while(right-left>1) 40 { 41 mid=(left+right)/2; 42 if(b[mid]>a[i].y) 43 right=mid; 44 else 45 left=mid; 46 } 47 b[right]=a[i].y; 48 } 49 } 50 printf("%d ",len); 51 } 52 return 0; 53 }//二分法减少时间!
这个题目看起来好像有思路,但就无从下手!
见大牛的:http://blog.csdn.net/freezhanacmore/article/details/9746771
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 7 const int maxn = 210; 8 int a[maxn], b[maxn]; 9 int dp[maxn]; 10 int n; 11 12 int LCIS(int n,int m) 13 { 14 memset(dp,0,sizeof(dp)); 15 for(int i = 1; i <= n; i++) 16 { 17 int tmp = 0; 18 for(int j = 1; j <= m; j++) 19 { 20 if(a[i] > b[j]) 21 tmp = max(tmp,dp[j]); 22 else if(a[i] == b[j]) 23 dp[j] = max(dp[j],tmp+1); 24 } 25 } 26 int ans = 0; 27 for(int i = 1; i <= m; i++) 28 ans = max(ans, dp[i]); 29 return ans; 30 } 31 32 int main() 33 { 34 int T; 35 scanf("%d", &T); 36 while(T--) 37 { 38 scanf("%d", &n); 39 for(int i = 1; i <= n; i++) 40 { 41 scanf("%d", &a[i]); 42 b[n-i+1] = a[i]; 43 } 44 int ans = 1; 45 for(int i = 1; i < n; i++) 46 { 47 ans = max(ans, 2*LCIS(i, n-i)); //不重叠 48 ans = max(ans, 2*LCIS(i+1, n-i)-1); //最坏恰好重叠一人 49 } 50 printf("%d ", ans); 51 } 52 return 0; 53 }