[ACM_动态规划] 最长上升子序列(LIS)

问题描述:给n个数,找出最长子序列并输出
问题分析: 本题是DAG(有向无环图)最长路问题,设d[i]为以i结尾的最长链的长度,则状态转移方程为:d[i]=max{0,d[j]|j<i && A[j]<A[i]}+1 ;
solve one: 这里用map[i][j]存储第i个和第j个的关系0-1邻接矩阵;套用标准解DAG的模板,利用dfs求解
#include<iostream>

#include<algorithm>

using namespace std;

#define maxn 1000+5





int d[maxn],n,map[maxn][maxn];    //d[]用来存储以i结尾的最大长度,map[i][j]满足要求OK()关系的邻接矩阵

int A[maxn];



bool ok(int i,int j){

    return j<i && A[j]<A[i];

}



int dfs(int cur)                  //深搜,记忆化搜索

{

    if( d[cur] > 0) return d[cur];//已经找过的直接输出

    d[cur] = 1;                   //没找的先付初值1,然后深搜寻找

    for(int i=1;i<=n;i++)

    {

        if( map[cur][i] && d[cur] < dfs(i)+1)

        {

            d[cur] = dfs(i)+1;

        }

    }

    return d[cur];

}

void out(int i)                   //反向追踪找到选取图形的标号

{

    for(int j=1;j<=n;j++)

    {

        if( map[i][j] && d[i] == d[j]+1)

        {

            out(j);

            break;

        }

    }

    cout << A[i]<< " ";//放在上面是倒着输出,下面是睁着输出

}



int main(){

    

    for(;cin>>n && n;){



        int i,j;

        

        for(i=1;i<=n;i++){                           //输入

            cin>>A[i];

        }



        memset(map,0,sizeof(map));                   //构造一个ok关系的0-1邻接矩阵

        for(i=1;i<=n;i++)

            for(j=1;j<=n;j++)

                if(ok(i,j))

                    map[i][j]=1;



        memset(d,0,sizeof(d));                       //深搜记忆化完成d[]表

        for(i=1;i<=n;i++){

            dfs(i);

        }





        int max=0,ds;                                //找出d[]的最大值并用ds存储尾链位置

        for(i=1;i<=n;i++){

            if(max<d[i]){

                max=d[i];

                ds=i;

            }

        }



        cout<<max<<'\n';

        out(ds);cout<<'\n';

    }

    return 0;

}
View Code
solve two:正向求解,边输边计算d[]的值
#include<iostream>

#include<algorithm>

using namespace std;

#define maxn 1000+5

#define INF 1<<31

int A[maxn],d[maxn],n;

void out(int i)                   //反向追踪找到选取图形的标号

{

    for(int j=1;j<=n;j++)

    {

        if(i>j && A[i]>A[j] && d[i] == d[j]+1)

        {

            out(j);

            break;

        }

    } 

    cout <<A[i]<< " ";

}



int main(){

    int i,j;

    while(cin>>n){

        memset(d,0,sizeof(d));



        int maxx=-INF,ds;

        for(i=1;i<=n;i++){

            cin>>A[i];



            int max=-INF;

            for(j=1;j<i;j++)

                if(A[i]>A[j] && max<d[j])

                    max=d[j];

            d[i]=(max==-INF ? 1: max+1);



            if(maxx<d[i]){maxx=d[i];ds=i;}

        }



        cout<<maxx<<'\n';

        out(ds);

        cout<<'\n';

    }

}
View Code

 

你可能感兴趣的:(动态规划)