1. O(n^2)
传统的求解方法 ,思路为dp,状态转移方程为 dp[i]=max( dp[j]+1,1)
即到目前的i为止,对前面出现的a[j](j<i)进行遍历 ,如果出现了a[i]>a[j]的情况 ,就使用状态转移方程。
转移方程代表了两种可能 ,第一种为第i个元素自己成为一个上升的队列 ,或者是由于前面的a[j]<a[i] 所以在
dp[j]的基础之上形成了dp[i] = dp[j]+1 但前提是a[i]>a[j]
# include <stdio.h>
int a[500];
int dp[500];
int maxx=1;
int n;
void lis(){
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(a[i]>a[j]){
if(dp[i]<dp[j]+1){
dp[i]=dp[j]+1;
}
}
}
if(dp[i]>maxx)
maxx=dp[i];
}
}
void output(){
for(int i=n;i>=0;i--){
if(dp[i]==maxx){
printf("%d--",a[i]);
maxx--;
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
maxx = 1;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
lis();
printf("最大的长度为%d\n",maxx);
output();
}
return 0;
}
2. 第二种方法 LIS+LCS 把原序列与从小到大排序后的序列做LCS(最长公共子序列),就能求出LIS
顺便写了一下快排 还有可以再开一个数组来记录求LCS的路径 来解决输出的问题
# include<stdio.h>
# include<string.h>
int n;
int a[500];
int b[500];
int dp[500][500];
int res[500][500];
void swap(int *a,int i,int j){
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
void qsort(int *a,int left,int right){
if(left>=right) return ;
int len = left+1;
for(int i=left+1;i<=right;i++){
if(a[i]<a[left]){
swap(a,i,len);
len++;
}
}
len--;
swap(a,left,len);
qsort(a,left,len-1);
qsort(a,len+1,right);
}
void LCS(){
memset(dp,0,sizeof(dp));
memset(res,0,sizeof(res));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i-1]==b[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
res[i][j]=1;
}
else if(dp[i-1][j]>dp[i][j-1])
{
dp[i][j]=dp[i-1][j];
res[i][j]=2;
}
else {
dp[i][j]=dp[i][j-1];
res[i][j]=3;
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
qsort(a,0,n-1);
printf("最长上升子序列为:");
for(int i=0;i<n;i++){
printf("%d ",a[i]);
}
LCS();
printf("\nLIS的长度为:");
printf("%d\n",dp[n][n]);
int i=n,j=n;
int len=dp[n][n];
while(len){
if(res[i][j]==1){
printf("%d ",a[i-1]);
i--;
j--;
len--;
}
else if(res[i][j]==2){
i--;
}else if(res[i][j]==3){
j--;
}
}
}
return 0;
}
思路: dp[i] 所表示的意思为 在如果LIS的长度为i的话 dp[i]所保存的就是长度为i的LIS的末尾数最小的值
但是这个算法有些问题 就是他求LIS的速度是非常快的 但是如果要输出LIS的话 貌似有点困难
# include <stdio.h>
int n;
int a[500];
int dp[500];
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
dp[1]=a[0];
int len =1;
for(int i=1;i<n;i++){
int left=1;
int right=len;
while(left<=right){
int mid = (left+right)/2;
if(a[i]<dp[mid]) right= mid-1;
else left=mid+1;
}
dp[left] = a[i];
if(left>len) len++;
}
printf("%d\n",len);
}
return 0;
}
原文:http://blog.csdn.net/xws117/article/details/45438917