[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

 

posted @ 2013-07-27 15:08  beautifulzzzz  阅读(604)  评论(0编辑  收藏  举报