区间DP题目总结

Posted roni-i

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间DP题目总结相关的知识,希望对你有一定的参考价值。

1:给出一个括号字符串,问这个字符串中符合规则的最长子串的长度。

【分析】区间DP要覆盖整个区间,那么要求所有情况的并集。

先想出状态方程:

dp[i][j]:i ~ j区间内最大匹配数目
输出:dp[0][n-1](从0开始)

区间DP最先想到的是就是:

1.边界情况初始化

2.for枚举区间长度,一般从第二个开始

3.for枚举起点

4.直接求得终点

5.若括号匹配的情况,相当于外围是ok的,继续深入看内部,左端点右移&右端点左移+2(因为外围匹配,数目+26.一般情况就是枚举断点k,打擂台求匹配数目最大值

7.输出整个区间的最大匹配数

 

 

【逆序枚举区间长度】

技术分享图片
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,x,n) for(int i=(x); i<=(n); i++)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e18;
const int maxm = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int mod = 10056;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn = 10010;
int t,n,m,a[maxn],x,y,w;
int dp[110][110],ans;
string s;
int tot=0;
/*
[题意]:给出一个括号字符串,问这个字符串中符合规则的最长子串的长度。

dp[i][j]:i~j区间内最大匹配数
输出:dp[1][n]

match:
dp[i][j] = dp[i+1][j-1]+2;


for(k:1..j)
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);

((()))
()()()
([]])
)[)(
([][][)
end

6
6
4
0
6
*/
bool match(int L,int R)
{
    return s[L]==(&&s[R]==) || s[L]==[&&s[R]==];
}
int main()
{
    while(cin>>s)
    {
        if(s=="end") break;
        ms(dp,0);
        n=s.size();
        for(int i=n-1;i>=0;i--)//枚举区间长度
        {
            for(int j=i+1;j<n;j++)
            {
                if(match(i,j))
                    dp[i][j]=max(dp[i][j],dp[i+1][j-1]+2);
                for(int k=i;k<j;k++)
                    dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
            }
        }
        printf("%d
",dp[0][n-1]);
    }
}
POJ - 2955 Brackets

 【顺序】

技术分享图片
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,x,n) for(int i=(x); i<=(n); i++)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e18;
const int maxm = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int mod = 10056;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn = 10010;
int t,n,m,a[maxn],x,y,w;
int dp[110][110],ans;
string s;
int tot=0;
/*
[题意]:给出一个括号字符串,问这个字符串中符合规则的最长子串的长度。

dp[i][j]:i~j区间内最大匹配数
输出:dp[1][n]

match:
dp[i][j] = dp[i+1][j-1]+2;


for(k:1..j)
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);

((()))
()()()
([]])
)[)(
([][][)
end

6
6
4
0
6
*/
bool match(int L,int R)
{
    return s[L]==(&&s[R]==) || s[L]==[&&s[R]==];
}
int main()
{
    while(cin>>s)
    {
        if(s=="end") break;
        ms(dp,0);
        n=s.size();
        for(int l=1;l<n;l++)//枚举区间长度
        {
            for(int i=0;i+l<n;i++)//起点
            {
                int j=i+l;//终点
                if(match(i,j))
                    dp[i][j]=max(dp[i][j],dp[i+1][j-1]+2);
                for(int k=i;k<j;k++)
                    dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
            }
        }
        printf("%d
",dp[0][n-1]);
    }
}
括号匹配

 

以上是关于区间DP题目总结的主要内容,如果未能解决你的问题,请参考以下文章

区间DP总结

Java 求解划分字母区间

区间DP小结

石子合并2——区间DP这是道经典入门例题/试手模板

转载+删改:算法讲解之Dynamic Programing —— 区间DP [变形:环形DP]

区间DP问题总结