zoukankan      html  css  js  c++  java
  • 最长公共子序列LCS


    根据题目数据范围可以知道算法的时间复杂度应当是O(nlogn)。具体思路应当是将最长公共子序列问题转到最长上升子序列(LIS问题有时间复杂度O(nlogn))。具体可以参考这篇文章:最长上升子序列
    例如:

    求上面两个序列的最长公共子序列,可以将上面的的序列 1 6 5 4 3 2 转换成 1 2 3 4 5 6。即有1->1 , 6->2 , 5->3 , 4->4 , 3->5 , 2->6。的对应方法。最后转换成下面这个样子。

    求两个序列的公共子序列就是求下面序列的最长上升子序列。下面的代码中translate()函数就是转换的方法。

    代码如下:

    #include<iostream>//根据题目范围知道这道题要用nlogn 的算法,用n^2的算法会超时,将LCS的问题转化为LIS的问题是解决本题的关键。
    #include<algorithm>
    using namespace std;
    const int maxn = 100005;
    int n;
    int a[maxn], b[maxn],v[maxn],id[maxn];// id[x] : x被编成了几号
    //int dp[maxn];
    inline void input()//输入函数
    {
    	cin >> n;
    	for (int i = 1;i <= n;i++)
    		cin >> a[i];
    	for (int i = 1;i <= n;i++)
    		cin >> b[i];
    }
    inline int query()
    {
    	v[1] = a[1];
    	int ans = 1;
    	for (int i = 2;i <= n;i++)
    	{
    		if (a[i] > v[ans])
    			v[++ans] = a[i];
    		else//为了使上升子序列最长,应当使序列中的值之间相差尽可能的小。   *p=a[i];的目的就是舍弃之前的值,用新的a[i]来顶替它。
    		{
    			int* p = lower_bound(v + 1, v + 1 + ans, a[i]);
    			*p = a[i];
    		}
            
    	}
    	return ans;
    	/*for(int i=1;i<=n;i++)//朴素做法,时间复杂度为n^2
    		for (int j = n;j >=1;j--)
    		{
    			if (a[i] == b[j])
    				dp[j] = max(dp[j - 1] + 1, dp[j]);
    			else
    				dp[j] = max(dp[j], dp[j - 1]);
    		}
    	return dp[n];*/
    }
    inline void translate()
    {
    	for (int i = 1;i <= n;i++)//将数字进行转化的精髓
    		id[b[i]] = i;     
    	for (int i = 1;i <= n;i++)
    		a[i] = id[a[i]];
        /*for (int i = 1;i <= n;i++)
            b[i]=i;*/
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	input();
    	translate();
        /*for(int i=1;i<=n;i++)
        cout<<a[i]<<" ";
        cout<<endl;
         for(int i=1;i<=n;i++)
        cout<<b[i]<<" ";
        cout<<endl;*/
    	int k = query();
    	cout << k << endl;
    }
    

    以上是关于这道模板题的讲解。下面来对LCS问题进行分析。复杂度为O(n^2)。
    对于长度为n的序列A和长度为m的序列B。
    具体可以这样思考:
    dp[i][j]是长度为i的序列A和长度为j的序列B的最长公共子序列。
    1.A[i]==B[j],则有dp[i][j]=dp[i-1][j-1]+1;
    2.A[i]!=B[j], 则有dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    代码如下:

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int A[105],B[105];
    int dp[105][105];
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        cin>>A[i];
        for(int i=1;i<=m;i++)
        cin>>B[i];
        for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
           {
               if(A[i]==B[j])
                   dp[i][j]=dp[i-1][j-1]+1;
               else
                   dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
           }
        cout<<dp[n][m]<<endl;
    }
    
    

    参考资料:
    https://www.zhihu.com/question/23995189
    https://www.luogu.com.cn/blog/pks-LOVING/junior-dynamic-programming-dong-tai-gui-hua-chu-bu-ge-zhong-zi-xu-lie

  • 相关阅读:
    测试
    python+selenium
    selenium使用execute_script方法执行JavaScript
    Selenium之动作链(ActionChains)
    angular组件数据
    angular
    数据库sql查询习题
    django
    集合框架Collection
    sql语句中select、 from、 where、 group by 、having、 order by的执行顺序分析
  • 原文地址:https://www.cnblogs.com/Acapplella/p/13292572.html
Copyright © 2011-2022 走看看