HDU3351 动态规划,经验总结

Seinfeld

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 222    Accepted Submission(s): 136

Problem Description
I’m out of stories. For years I’ve been writing stories, some rather silly, just to make simple problems look difficult and complex problems look easy. But, alas, not for this one.
You’re given a non empty string made in its entirety from opening and closing braces. Your task is to find the minimum number of “operations” needed to make the string stable. The definition for being stable is as follows:
1. An empty string is stable.
2. If S is stable, then {S} is also stable.
3. If S and T are both stable, then ST (the concatenation of the two) is also stable.
All of these strings are stable: {}, {}{}, and {{}{}}; But none of these: }{, {{}{, nor {}{.
The only operation allowed on the string is to replace an opening brace with a closing brace, or visa-versa.
 

 

Input
Your program will be tested on one or more data sets. Each data set is described on a single line. The line is a non-empty string of opening and closing braces and nothing else. No string has more than 2000 braces. All sequences are of even length.
The last line of the input is made of one or more ’-’ (minus signs.)

 

 

Output
For each test case, print the following line:
k. N
Where k is the test case number (starting at one,) and N is the minimum number of operations needed to convert the given string into a balanced one.
Note: There is a blank space before N.
 

 

Sample Input
  
  
}{ {}{}{} {{{} ---
 

 

Sample Output
  
  
1. 2 2. 0 3. 1
 

 

Source
 

 

Recommend
lcy
代码:
#include<iostream>
using namespace std;
int a[2010][2010];
int s[2010];
char ss[2010];
int main()
{
    int times=0;
    while(1)
    {
        ++times;
        memset(ss,'/0',sizeof(ss));
        memset(s,0,sizeof(s));
        memset(a,10000,sizeof(a));
        cin>>&ss[1];
        if(ss[1]=='-')
        break;
        int l=0;
        for(int i=1;ss[i]!='/0';++i)
        {
            l=i;
            if(ss[i]=='}')
            s[i]=-1;
            else s[i]=1;
        }
        if(s[1]==1)
        a[1][1]=0;
        else a[1][1]=1;
        for(int i=1;i<l;++i)
        for(int j=0;j<l;++j)
        {
            if(a[i][j]==10000)
            continue;
            if(s[i+1]==1)
            {
                if(j-1>=0)
                {
                    int t=a[i+1][j-1];
                    if(t>a[i][j]+1)
                    a[i+1][j-1]=a[i][j]+1;
                }
                if(j+1<=l)
                {
                    int t=a[i+1][j+1];
                    if(t>a[i][j])
                    a[i+1][j+1]=a[i][j];
                }
            }
            if(s[i+1]==-1)
            {
                if(j-1>=0)
                {
                    int t=a[i+1][j-1];
                    if(t>a[i][j])
                    a[i+1][j-1]=a[i][j];
                }
                if(j+1<=l)
                {
                    int t=a[i+1][j+1];
                    if(t>a[i][j]+1)
                    a[i+1][j+1]=a[i][j]+1;
                }
            }
        }
        printf("%d. %d/n",times,a[l][0]);
    }
    return 0;
}
月赛的一题,废话不多说了,此题用栈就可以O(n)解,但是ZOJ有一题和这个题类似,但是它把每个括号都付了权值,最后求最小或者最大的权值和,这样就只能有DP来解了。
这个DP 完全是自己猜想出来的,因为没有什么经验,所以仅有这点成功的经验赶快记录下来供后来回忆。
此题DP为O(n2)时间。基本思路是把括号抽象成数字1=(和-1=)
设置DP的矩阵为2维a[i][j]
i表示这个串的钱i项组成的子串 j表示当前子串有多少个(多余的积累,即前i项和为多少
根据第i+1项的值即s[i+1]的大小,可以有分两种情况讨论递推方程
当s[i+1]=1时,a[i+1][j+1]=a[i][j];(即不对"("进行变换)
a[i+1][j-1]=a[i][j]+1;(将“("进行变换,需要一步操作)
同理当s[i+1]=-1时,a[i+1][j-1]=a[i][j];(即不对")"进行变换)
a[i+1][j+1]=a[i][j]+1;(将“)"进行变换,需要一步操作)
由于只要知道a[i][x]就可以知道a[i][x+1]和a[i][x-1],所以确定计算顺序为从a[1][1]->a[2][2]->a[2][0]->a[3][1]->a[3][3]...
即以列优先的顺序进行计算,通过比较确定每个a[i][j]的最小值,最后a[l][0]即为答案。
注意i和j不能越过边界。
当前对DP的认识:主要是自低向上的顺序,a[i][j][k]...保存要进行比较求得的当前子问题的临时解或最优解。其中a的维度决定DP的时间效率。各个维度表示不同的信息。比如此题i表示对原问题的一种划分,a[i]表示原串的前i个元素组成的子串,即按照线性进行划分。也可能这个划分不是线性的,比如LCS问题中,将原问题划分为2维的子问题,即由两个不同长度串决定不同的子问题。具体的划分方法由问题本身确定。a其他的维度可以是当前子问题的某种参数,某种特性,这种特性影响着最优解的形成,所以DP时需要将它包括在内考虑。比如此题中j表示当前字串和为多少,此和影响着是否最后能形成最优解。当然这个维度也是可能不止一个。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值