zoukankan      html  css  js  c++  java
  • [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<<'
    ';
            out(ds);cout<<'
    ';
        }
        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<<'
    ';
            out(ds);
            cout<<'
    ';
        }
    }
    View Code
  • 相关阅读:
    ArrayList集合封装 类 并通过方法调用
    ArrayList集合的基本操作
    方法的重复定义和重载
    方法间值的传递,二维数组的定义和遍历
    赋值运算,逻辑运算符,引用数据类型
    Javase;jdk的安装调试;基础语法和变量以及基础数据类型
    E-R画图规则和数据库设计的三大范式
    sql多表查询和子查询
    sql约束的使用
    sql表操作的基础语法
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/3219522.html
Copyright © 2011-2022 走看看