线性dp之复习lis、lcs、线性回文串(uva11584,codeforce607B)

线性dp

lis

最长的递增子序列

  • 初始化值时应该是1(如果递增也最少是这个元素,最少是1)
  • dp[i]表示到这个之前的最大递增的数
for(int i = 0;i < len; i++){
	dp[i] = 1;
	for(int j = 0;j < i; j++){
		if(a[j] < a[i]) dp[i] = max(dp[i],dp[j]+1);
	}
	//筛出最大值
	ans = max(ans,dp[i]);
}

lcs

最长的相同公共子序列

  • 初始化值不用变,都是零。
  • dp[i][j] 表示第一个串的第i个之前和第二个串的第j个之前匹配的最大值。
for(int i = 1;i <= a.size(); i++){
	for(int j = 1;j <= b.size(); 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]);
	}
}

回文串

bool is(int l ,int r){}   //判断这个区间是否为回文串
for(int i = 1;i < str.length();i++){
	//初始化
	dp[i] = i+1;
	for(int j = 1;j <= i;j++)
		if(is(j,i)) dp[i] = min(dp[i],dp[j-1]+1);
}

题目大意:
给出一个字符串,看最少拆成多少回文子串。

//
//  main.cpp
//  线性dp_切割出回文串
//
//  Created by 陈冉飞 on 2019/9/11.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#define maxn 10010
char s[maxn];
int dp[maxn];   //dp[i][j]表示区间i到区间j的最小的回文串的长度

bool is_ok(int l,int r){
    while (l <= r) {
        if (s[l] == s[r]) {
            l++;r--;
        }else return false;
    }
    return true;
}

int main(int argc, const char * argv[]){
    scanf("%s",s+1);
    int len = strlen(s+1);
//    //检验是否为回文串
//    for (int i = 1; i <= len; i++)
//        for (int j = 1; j <= i; j++)
//            cout<<j<<"  "<<i<<"  "<<is_ok(j, i)<<endl;
    
    //init
    for (int i = 1; i <= len; i++) {
        //初始化
        dp[i] = i+1;
        for (int j = 1; j <= i; j++)
            if (is_ok(j, i)) dp[i] = min(dp[i],dp[j-1]+1);
    }
    cout<<dp[len]<<endl;
    return 0;
}

codeforce 607B
题目大意:给出一个数组,然后看每次拿出一个回文子串,然后看最少多少次把整个数组拿完

//
//  main.cpp
//  线性dp_逐次拿出回文串
//
//  Created by 陈冉飞 on 2019/9/12.
//  Copyright © 2019 陈冉飞. All rights reserved.
//

#include <iostream>
using namespace std;
#define maxn 505
int dp[maxn][maxn],n,a[maxn];      //dp[i][j] 为从i到j这个区间中最少的次数
#define INF 0x3f3f3f
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))

int main(int argc, const char * argv[]) {
    scanf("%d",&n);
    //初始化
    cl(dp, INF);
    for (int i = 1; i <= n; i++) {scanf("%d",&a[i]);dp[i][i] = 1;}
    //先遍历长度
    for (int len = 1; len <= n; len++) {
        for (int i = 1; i+len <= n; i++) {
            int j = i+len;
            if (a[i] == a[j]){
                dp[i][j] = len;
                //排除aa这种情况的特判
                if (dp[i][j]!= 1) dp[i][j] = dp[i+1][j-1];
            }
            for (int k = i; k <= j; k++) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]);
        }
    }
    cout<<dp[1][n]<<endl;
    return 0;
}

发布了95 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43345204/article/details/100753221