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));
    }
    

      

      

    编译人生,运行世界!
  • 相关阅读:
    uva 147 Dollars
    hdu 2069 Coin Change(完全背包)
    hdu 1708 Fibonacci String
    hdu 1568 Fibonacci
    hdu 1316 How Many Fibs?
    poj 1958 Strange Towers of Hanoi
    poj 3601Tower of Hanoi
    poj 3572 Hanoi Tower
    poj 1920 Towers of Hanoi
    筛选法——素数打表
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4778309.html
Copyright © 2011-2022 走看看