zoukankan      html  css  js  c++  java
  • LIS && LCS && LCIS && LPS && MCS模板

    1. LIS (Longest Increasing Subsequence)

    O (n^2):

    /*
    	LIS(Longest Increasing Subsequence)	最长上升子序列 O (n ^ 2)
    	状态转移方程:dp[i] = max (dp[j]) + 1 (a[j] < a[i],1 <= j < i)
    	附带有print输出路径函数
    */
    void LIS(void)	{
    	int ret = 0, last = 0;
    	for (int i=1; i<=n; ++i)	{
    		dp[i] = 1;	fa[i] = -1;
    		for (int j=1; j<i; ++j)	{
    			if (a[j] < a[i] && dp[i] < dp[j] + 1)	{
    				dp[i] = dp[j] + 1;	fa[i] = j;
    			}
    		}
    		if (ret < dp[i])	{
    			ret = dp[i];	last = i;
    		}
    	}
    
    	printf ("%d
    ", ret);
    	print (last);	puts ("");
    }
    
    void print(int x)	{
    	if (fa[x] != -1)	{
    		print (fa[x]);	printf (" %d", a[x]);
    	}
    	else	printf ("%d", a[x]);
    }
    

    O (nlogn):

    /*
    	LIS 二分查找优化, O(nlogn)
    	设当前最长递增子序列为len,考虑元素a[i]; 若d[len]<a[i],则len++,并使d[len]=a[i]; 
    	否则,在d[1~len]中二分查找第一个大于等于a[i]的位置j,使d[j]=a[i]。附上打印路径代码(准确性未知)
    */
    void LIS(void)	{
    	int len = 1;	d[1] = a[1];	fa[1] = -1;
    	for (int i=2; i<=n; ++i)	{
    		if (d[len] < a[i])	{
    			d[++len] = a[i];
    			pos[len] = i;	fa[i] = pos[len-1];
    		}
    		else	{
    			int j = lower_bound (d+1, d+1+len, a[i]) - d;
    			d[j] = a[i];
    			pos[j] = i;	fa[i] = (j == 1) ? -1 : pos[j-1];
    		}
    	}
    	printf ("%d
    ", len);
    	vector<int> res;	int i;
    	for (i=pos[len]; ~fa[i]; i=fa[i])	res.push_back (a[i]);
    	res.push_back (a[i]);
    	for (int i=res.size ()-1; i>=0; --i)	printf ("%d%c", res[i], i == 0 ? '
    ' : ' ');
    }
    

    2. LCS (Longest Common Subsequence)

    /*
        LCS(Longest Common Subsequence):
            状态转移方程:dp[i][j] = dp[i-1][j-1] + 1; (s[i-1] == t[i-1])
                        dp[i][j] = max (dp[i][j-1], dp[i-1][j]);(s[i-1] != t[i-1])
            可滚动数组优化。附带有print输出路径函数。
    */
    void LCS(void)  {
        memset (dp, 0, sizeof (dp));
        memset (fa, 0, sizeof (fa));
        for (int i=0; i<=lens; ++i)    fa[i][0] = -1;
        for (int i=0; i<=lent; ++i)    fa[0][i] = 1;
    
        for (int i=1; i<=lens; ++i) {
            for (int j=1; j<=lent; ++j) {
                if (s[i-1] == t[j-1])   {
                    dp[i][j] = dp[i-1][j-1] + 1;
                    fa[i][j] = 0;
                }
                else if (dp[i-1][j] >= dp[i][j-1])  {
                    dp[i][j] = dp[i-1][j];
                    fa[i][j] = -1;
                }
                else    {
                    dp[i][j] = dp[i][j-1];
                    fa[i][j] = 1;
                }
            }
        }
    
        printf ("%d
    ", dp[lens][lent]);
        print (lens, lent); puts ("");
    }
    
    void print(int x, int y)    {
        if (!x && !y)   return ;
        if (fa[x][y] == 0)  {
            print (x-1, y-1);    printf ("%c", s[x-1]);
        }
        else if (fa[x][y] == -1)    {
            print (x-1, y);    printf ("%c", s[x-1]);
        }
        else    {
            print (x, y-1);    printf ("%c", t[y-1]);
        }
    }
    

    3. LCIS (Longest Common Increasing Subsequence)

    /*
    	LCIS(Longest Common Increasing Subsequence) 最长公共上升子序列
    	状态转移方程:a[i] != b[j]: dp[i][j] = dp[i-1][j]; 
    				  a[i] == b[j]: dp[j]=max(dp[j],dp[k]); (1<=k<j&&b[k]<b[j])  
    	打印路径时按照b[i]来输出
    */
    void LCIS(void)	{
    	memset (dp, 0, sizeof (dp));
    	memset (fx, 0, sizeof (fx));
    	memset (fy, 0, sizeof (fy));
    	int sx = 0, sy = 0;
    	int ret = 0, k = 0;
    	for (int i=1; i<=n; ++i)	{
    		k = 0;
    		for (int j=1; j<=m; ++j)	{
    			dp[i][j] = dp[i-1][j];									//以a[]为主循环,每个a[i],去找每个b[j]
    			fx[i][j] = i - 1;	fy[i][j] = j;
    			if (a[i] == b[j] && dp[i][j] < dp[i][k] + 1)	{		//满足LCS
    				dp[i][j] = dp[i][k] + 1;							//在1~j-1找到b[k]<a[i],满足LIS,在b[k]上更新dp
    				fx[i][j] = i;	fy[i][j] = k;
    			}
    			else if (a[i] > b[j] && dp[i][j] > dp[i][k])	k = j;	//找到最优的k
    			if (ret < dp[i][j])	{
    				ret = dp[i][j];										//更新所有dp中的最大值
    				sx = i, sy = j;
    			}
    		}
    	}
    	printf ("%d
    ", ret);
    	fir = true;
    	print (sx, sy, -1);	puts ("");
    }
    
    void print(int x, int y, int last)	{		//bool fir;
    	if (x == 0 || y == 0)	return ;
    	print (fx[x][y], fy[x][y], y);
    	if (y != last)	{
    		if (fir)	printf ("%d", b[y]), fir = false;
    		else	printf (" %d", b[y]);
    	}
    }
    

    4. LPS (Longest Palidromic Subsequence)

    /*
        LCS的思想,dp[i][j]表示i到j的最长回文串长度,状态转移方程:
            1. dp[j][j+i-1] = dp[j+1][j+i-2] + 2;   (str[j] == str[j+i-1])
            2. dp[j][j+i-1] = max (dp[j+1][j+i-1], dp[j][j+i-2]);   (str[j] != str[j+i-1])
        ans[1][len]是string类型,记录LPS字符
    */
    void LPS(void)  {
        int len = strlen (str + 1);
        memset (dp, 0, sizeof (dp));
        for (int i=1; i<=len; ++i)  dp[i][i] = 1;
        for (int i=1; i<=len; ++i)  ans[i][i] = str[i];
    
        for (int i=2; i<=len; ++i)   {              //区间长度
            for (int j=1; j+i-1<=len; ++j)  {       //[j, j+i-1]
                if (str[j] == str[j+i-1])   {
                    if (i == 2) {
                        dp[j][j+i-1] = 2;
                        ans[j][j+i-1] = ans[j][j] + ans[j+i-1][j+i-1];  continue;
                    }
                    dp[j][j+i-1] = dp[j+1][j+i-2] + 2;
                    ans[j][j+i-1] = str[j] + ans[j+1][j+i-2] + str[j+i-1];
                }
                else if (dp[j+1][j+i-1] > dp[j][j+i-2]) {
                    dp[j][j+i-1] = dp[j+1][j+i-1];
                    ans[j][j+i-1] = ans[j+1][j+i-1];
                }
                else if (dp[j][j+i-2] > dp[j+1][j+i-1]) {
                    dp[j][j+i-1] = dp[j][j+i-2];
                    ans[j][j+i-1] = ans[j][j+i-2];
                }
                else    {
                    dp[j][j+i-1] = dp[j+1][j+i-1];
                    ans[j][j+i-1] = min (ans[j+1][j+i-1], ans[j][j+i-2]);
                }
            }
        }
        int mlen = dp[1][len];
        for (int i=0; i<mlen; ++i)  {
            printf ("%c", ans[1][len][i]);
        }
        puts ("");
    }
    

    5. MCS (Maximum Continuous Subsequence)

    O (n):

    /*
    	MCS (Maximum Continuous Subsequence) 最大子序列和 O (n)
    	1. DP	2. 前缀
    	若有多个答案输出第一个,均给出区间端点
    */
    void MCS(int n)	{
    	int l = 0, ll = 0, rr = 0;
    	int sum = -INF, mx = -INF;
    	for (int i=1; i<=n; ++i)	{
    		if (sum + a[i] < a[i])	{
    			sum = a[i];	l = i;
    		}
    		else	sum += a[i];
    		if (sum > mx)	{
    			mx = sum;	ll = l, rr = i;
    		}
    	}
    	printf ("%d %d %d
    ", mx, ll, rr);
    }
    

    O (n) another:

    //O (n) //another
    void MCS(int n)	{
    	int l = 0, ll = 0, rr = 0;
    	int sum = 0, mx = -INF, mn = 0;
    	for (int i=1; i<=n; ++i)	{
    		sum += a[i];
    		if (sum - mn > mx)	{
    			mx = sum - mn;	ll = l;	rr = i;
    		}
    		if (sum < mn)	{
    			mn = sum;	l = i;
    		}
    	}
    	printf ("%d %d %d
    ", mx, ll + 1, rr);
    }
    

    O (nlogn):

    //O (nlogn)     //输出端点困难
    int MCS(int *a, int l, int r)   {
        if (l == r) {
            if (a[l] > 0)    return a[l];
            else    return 0;
        }
        int mid = (l + r) >> 1;
        int lmax = MCS (a, l, mid);
        int rmax = MCS (a, mid + 1, r);
         
        int lbmax = 0, lbsum = 0;
        for (int i=mid; i>=left; --i)   {  //之前写错了,应该是连续的
            lbsum += a[i];
            if (lbmax < lbsum)   lbmax = lbsum;
        }
        int rbmax = 0, rbsum = 0;
        for (int i=mid+1; i<=r; ++i) {
            rbsum += a[i];
            if (rbmax < rbsum)   rbmax = rbsum;
        }
     
        return max (lbmax + rbmax, max (lmax, rmax));
    }
    

      

      

    编译人生,运行世界!
  • 相关阅读:
    简单的JAVAWeb选课系统
    公文流转系统001
    第九周动手动脑
    JAVA文件操作
    动手动脑-异常处理
    个人NABCD
    水王(课堂作业)
    软件学习进度表07
    软件工程学习进度表06
    软件工程个人作业05(二维数组求最大子数组的和)
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4778309.html
Copyright © 2011-2022 走看看