您的位置:首页 > 产品设计 > UI/UE

poj 1141 Brackets Sequence 【DP&&备忘录】

2009-08-24 23:40 363 查看
题目如下:
Description
Let us define a regular brackets sequence in the following way:

1. Empty sequence is a regular sequence.
2. If S is a regular sequence, then (S) and [S] are both regular sequences.
3. If A and B are regular sequences, then AB is a regular sequence.

For example, all of the following sequences of characters are regular brackets sequences:

(), [], (()), ([]), ()[], ()[()]

And all of the following character sequences are not:

(, [, ), )(, ([)], ([(]

Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.
Input
The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.
Output
Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.
Sample Input
([(]

Sample Output
()[()]

解答:

用char *str 记录符号,Int * *state 记录符号数,state[i][j]表示str[i]……str[j]补全括号之后的括号数;

用string * *ans表示补全括号之后的串,ans[i][j]表示str[i]……str[j]补全括号之后的括号串

主要注意两句话:

第一句:If A and B are regular sequences, then AB is a regular sequence

那我们可以得出如下状态转移方程:

state[i][j]=min(state[i][k]+state[k+1][j])       (i<=k<=j)

ans[i][j]=ans[i][k]+ans[k+1][j]

第二句:If S is a regular sequence, then (S) and [S] are both regular sequences.

我们可以得到:

state[i][j]=min(state[i][j],state[i+1][j-1]+2)   if(match(str[i],str[j]))

ans[i][j]=str[i]+ans[i+1][j-1]+str[j]

值得注意的是初始化数据:

state[i][i]=2

state[i][j]=0   if(i>j);

以下是代码:

代码1是用了纯DP的方式

代码2用了备忘录。但是两者的基本思想都是一样的。

代码1:

#include<iostream>
#include<string>
using namespace std;
#define M 105

int state[M][M];
string ans[M][M];
char str[M];
int n;

bool Match(char x,char y)
{
if(x=='('&&y==')')
return true;
if(x=='['&&y==']')
return true;
return false;
}

void Init()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
{
state[i][j]=0;
ans[i][j]="";
}
for(i=1;i<=n;i++)
{
state[i][i]=2;
if(str[i]=='('||str[i]==')')
ans[i][i]="()";
else
ans[i][i]="[]";
}
}
void DP(){
int i,j,k;
//以下的双重循环用得妙,我也是第一次这么用的,解决了对角线的求解问题。
for(j=1;j<n;j++)
{
for(i=1;i+j<=n;i++)
{
state[i][i+j]=10000;
for(k=i;k<i+j;k++)
{
if(state[i][i+j]>(state[i][k]+state[k+1][i+j]))
{
state[i][i+j]=state[i][k]+state[k+1][i+j];
ans[i][i+j]=ans[i][k]+ans[k+1][i+j];
}
}
if(Match(str[i],str[i+j]))
{
if(state[i][i+j]>(state[i+1][j+i-1]+2)){
state[i][i+j]=state[i+1][j+i-1]+2;
ans[i][i+j]=str[i]+ans[i+1][i+j-1]+str[i+j];
}
}
}
}
}
int main()
{
cin>>str+1;
n=strlen(str+1);
Init();
DP();
cout<<ans[1]
<<endl;
return 0;
}
[/code]
代码2:

#include<iostream>
#include<string>
using namespace std;
#define M 105

int state[M][M]; //表示第i个括号到j个括号,配对之后的括号数
string ans[M][M]; //表示第i个括号到j个括号,配对之后的符号串
char str[M];
int n;

bool Match(char x,char y)
{
if(x=='('&&y==')')
return true;
if(x=='['&&y==']')
return true;
return false;
}

void Init()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
{
state[i][j]=0;
ans[i][j]="";
}
for(i=1;i<=n;i++)
{
state[i][i]=2;
if(str[i]=='('||str[i]==')')
ans[i][i]="()";
else
ans[i][i]="[]";
}
}
int DP(int i,int j){
int k;
if(state[i][j]>0)
return state[i][j];
if(i>j)
return 0;
int dist=99999;
for(k=i;k<j;k++)
{
if(dist>DP(i,k)+DP(k+1,j))
{
dist=DP(i,k)+DP(k+1,j);
ans[i][j]=ans[i][k]+ans[k+1][j];
}
if(Match(str[i],str[j]))
{
if(dist>DP(i+1,j-1)+2)
{
dist=state[i+1][j-1]+2;
ans[i][j]=str[i]+ans[i+1][j-1]+str[j];
}
}
}
state[i][j]=dist;
return dist;
}
int main()
{
cin>>str+1;
n=strlen(str+1);
Init();
DP(1,n);
cout<<ans[1]
<<endl;
return 0;
}
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: