dp训练第3题 XJTUOJ old56 GG与最新操作 dp-区间dp

“[”是开始操作A,“]”是结束操作A,“(”是开始操作B,“)“是结束操作B。定义这样的操作为合法操作序列。
1. 一个空的操作序列是合法操作序列
2. 先开始操作X(A 或 B),再进行一个合法操作序列,最后结束操作X,这样一个操作序列是一个合法操作序列
3. 把合法操作序列X和Y连起来,也是一个合法操作序列
如:
- (), [], (()), ()[()], (()()) 都是合法操作
- ([)], [[]), ( 都不是合法操作
GG有一本操作手册,在学习一个操作序列时,他发现这个序列可能不是一个合法序列,现在给出这个序列,请你回答最少需要往这个操作序列里面插入几次操作(插入“([])”中的一个字符算是插入一次操作),才能使这个操作序列变成合法操作序列。
Input
输入有多组数据,每组数据一行,只包括“([])”,长度不小于1,不超过100,至文件尾结束。保证数据数量小于等于15
Output
对每组数据,输出一行,即往这个操作序列里面最少插入的操作数目

这个操作真是可怕.
我竟然看了这道题一个小时,我都在想些什么啊….
状态表示: dp[i][j][i,j].dp[0,l1] d p [ i ] [ j ] 表 示 [ i , j ] 内 最 少 需 要 插 入 的 操 作 数 . d p [ 0 , l − 1 ] 即 为 答 案
边界情况: dp[i][i]=1 d p [ i ] [ i ] = 1
状态转移: dp[i][j]=minj1k=i{dp[i][k]+dp[k+1][j]} d p [ i ] [ j ] = m i n k = i j − 1 { d p [ i ] [ k ] + d p [ k + 1 ] [ j ] }
if(check(i,j)) i f ( c h e c k ( i , j ) ) dp[i][j]=min(dp[i][j],dp[i+1][j1]) d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i + 1 ] [ j − 1 ] )
注意j=i+1的边界条件就好.

这道题是按长度规模递增递推的dp.

/* LittleFall : Hello! */
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
inline void write(int x);
const int M = 100016;
int dp[200][200]; //[起点,终点]
int equal(char a,char b)
{
    return (a=='('&&b==')')||(a=='['&&b==']');
}
int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("in.txt","r",stdin);
    #endif
    //std::cin.sync_with_stdio(false); 

    char p[200];
    while(scanf("%s",p)!=EOF)
    {
        memset(dp,1,sizeof(dp));
        int l=strlen(p);
        for(int i=0;i<l;i++) 
            dp[i][i]=1;
        for(int k=1;k<l;k++) //偏移量(长度-1)
        for(int i=0;i<l-1;i++) //左边界,闭
        {
            int j=i+k;//右边界,闭
            for(int m=i;m<j;m++) //划分位置
                dp[i][j]=min(dp[i][j],dp[i][m]+dp[m+1][j]);
            if(equal(p[i],p[j]))
                dp[i][j]=min(dp[i][j],j-i>1?dp[i+1][j-1]:0);
        }
        printf("%d\n",dp[0][l-1] );
    }

    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值