码迷,mamicode.com
首页 > 编程语言 > 详细

zjnu(1183)——括号序列【基础算法?动态规划】——高级

时间:2015-08-28 00:53:39      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:动态规划   dp   区间dp   

首先,我只想声明一点,这道题有毒。。。我用char读入就错了,然而换成string读入就对了或者可以把定义char的数组开的大一点,原先1A的一题硬是纠结了老半天。

传送门:zjnu

题意:

就是对于一个组成的序列,添加尽量少的括号得到一个规则序列,并且输出这个序列的长度。

不过我学到了两种定义dp状态的方法:

1)定义dp[i][j]为i~j中需要添加的最少的括号数。这里我们记录s为一段字符的开始位置,e为一段字符的结束位置。

     ①当(a[s]==‘(‘&&a[e]==‘)‘)||(a[s]==‘[‘&&a[e]==‘]‘)时,dp[s][e]=min(dp[s][e],dp[s+1][e-1]); 

     ②当(a[s]==‘(‘&&a[e]!=‘)‘)||(a[s]==‘[‘&&a[e]!=‘]‘)时,dp[s][e]=min(dp[s][e],dp[s][e-1]+1);

     ③当(a[e]==‘)‘&&a[s]!=‘(‘)||(a[e]==‘]‘&&a[s]!=‘[‘)时,dp[s][e]=min(dp[s][e],dp[s+1][e]+1);

     ④然后当两个数中间还有其他数存在的时候,那么我们就用for,像石子归并那样,然后去更新dp[s][e]

最后输出的时候只要输出dp[0][len-1]+len就好了。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define inf 99999999
#define maxn 111
int main(){
	string a;
	cin>>a;
	int l=a.length();
	int dp[111][111];
	for(int i=0;i<l;i++) dp[i][i]=1;
	for(int len=2;len<=l;len++){
		for(int s=0;s<=l-len;s++){
			int e=s+len-1;
			dp[s][e]=inf;<span style="white-space:pre">		</span>//!!!
			if((a[s]=='('&&a[e]==')')||(a[s]=='['&&a[e]==']')) 
				dp[s][e]=min(dp[s][e],dp[s+1][e-1]);
			if((a[s]=='('&&a[e]!=')')||(a[s]=='['&&a[e]!=']')) 
				dp[s][e]=min(dp[s][e],dp[s][e-1]+1);
			if((a[e]==')'&&a[s]!='(')||(a[e]==']'&&a[s]!='[')) 
				dp[s][e]=min(dp[s][e],dp[s+1][e]+1);
			for(int k=s;k<e;k++){
				dp[s][e]=min(dp[s][e],dp[s][k]+dp[k+1][e]);
			}
		}
	}
	printf("%d\n",dp[0][l-1]+l);
}

2)第二种状态定义的和第一种有点不一样。

定义dp[i][j]为i~j的区间内符合规范的字符串的最短的长度。

当然在这里我们需要进行初始化,对于不同位置的dp,我们需要进行不同的计算。(这里初始化是很重要的)

当a[s]==‘(‘&&a[e]==‘)‘时,那么dp[s][e]=dp[s+1][e-1]+2;

否则的话,则去寻找跳板,然后更新dp[s][e]。

其实主要的思路就是先算出小区间的每个最短的长度,然后再根据小区间然后去更新大区间的值。

最后输出的直接是dp[0][len-1]就可以了。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111
#define inf 99999999
int main(){
	string a;
	cin>>a;
	int dp[111][111];
	int len=a.length();
	for(int i=0;i<len;i++){
		for(int j=0;j<len;j++){
			if(i==j) dp[i][j]=2;
			if(i>j) dp[i][j]=0;
			else if(i<j) dp[i][j]=inf;
		}
	}
	for(int l=2;l<=len;l++){
		for(int s=0;s<=len-l;s++){
			int e=s+l-1;
			if((a[s]=='('&&a[e]==')')||(a[s]=='['&&a[e]==']')){
				if(l>2) dp[s][e]=dp[s+1][e-1]+2;
				else dp[s][e]=2;
			}
			for(int k=s;k<e;k++){
				dp[s][e]=min(dp[s][e],dp[s][k]+dp[k+1][e]);
			}
		}
	}
	printf("%d\n",dp[0][len-1]);
}

理解!!!举一反三!!加油!!!


版权声明:本文为博主原创文章,未经博主允许不得转载。

zjnu(1183)——括号序列【基础算法?动态规划】——高级

标签:动态规划   dp   区间dp   

原文地址:http://blog.csdn.net/acmer_hades/article/details/48037653

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!