各种子序列问题
最长严格上升子序列
LIS问题,动归时间复杂度o(n2),可以用单调队列优化到o(nlogn)
http://blog.csdn.net/dangwenliang/article/details/5728363
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,dp[5005],orz[5005],ans = 0; int main(){ cin>>n; for(int i = 1;i <= n;i++) scanf("%d",&orz[i]); for(int i = 1;i <= n;i++){ dp[i] = 1; for(int j = 1;j < i;j++){ if(orz[i] > orz[j])dp[i] = max(dp[i],dp[j]+1); ans = max(ans,dp[i]); } } cout<<ans; return 0; }
#include <iostream> using namespace std; int find(int *a,int len,int n)//修改后的二分查找,若返回值为x,则a[x]>=n { int left=0,right=len,mid=(left+right)/2; while(left<=right) { if(n>a[mid]) left=mid+1; else if(n<a[mid]) right=mid-1; else return mid; mid=(left+right)/2; } return left; } int main(void) { int n,a[100],c[100],i,j,len;//新开一变量len,用来储存每次循环结束后c中已经求出值的元素的最大下标 while(cin>>n) { for(i=0;i<n;i++) cin>>a[i]; b[0]=1; c[0]=-1; c[1]=a[0]; len=1;//此时只有c[1]求出来,最长递增子序列的长度为1. for(i=1;i<n;i++) { j=find(c,len,a[i]); c[j]=a[i]; if(j>len)//要更新len,另外补充一点:由二分查找可知j只可能比len大1 len=j;//更新len } cout<<len<<endl; } return 0; }
合唱队形
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 200; int dp[maxn],dps[maxn],value[maxn],n; int main(){ cin>>n; for(int i =1;i <= n;i++) cin>>value[i]; dp[1] = dps[n] = 1; for(int i = 2;i <= n;i++){ for(int j = 1;j < i;j++){ if(dp[j] > dp[i] && value[i] > value[j]) dp[i] = dp[j]; } dp[i]++; } for(int i = n-1;i >= 1;i--){ for(int j = n;j > i;j--){ if(dps[j] > dps[i] && value[i] > value[j]) dps[i] = dps[j]; } dps[i]++; } int ans = 0; for(int i = 1;i <= n;i++) ans = max(ans,dp[i] + dps[i] - 1); cout<<n - ans; return 0; }