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\n", 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\n", 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 ? '\n' : ' ');
}

 

 

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\n", 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\n", 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\n", 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\n", 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));
}

 

  

 

  

posted @ 2015-09-02 13:14  Running_Time  阅读(261)  评论(0编辑  收藏  举报