ZOJ 1463 POJ1141 Brackets Sequence (区间DP) #by Plato
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=463
题意: 给一个括号序列,求 为使序列合法化所需要添加的最少括号书。要求输出合法化后的序列。
Idea: 比较明显的DP了,
f[i][j] 代表从 第i个元素到第j个元素所需要添加的最小括号数,
以i-j的距离扩大开始DP,
4种状态转移的方式:
条件 结果 路径
a[ i] – ‘)’ a[i]为左括号 f[i+1][j]+1 -1
‘(‘ – a[j] a[j]为右括号 f[i][j-1] +1 -2
a[i] – a[j] a[i]与a[j]匹配 f[i+1][j-1] -3
a[i] – a[m],a[m+1]-a[j] f[i][m]+ f[m+1][j] m
有关路径记录,有多种方案,这里采用的是 直接记录 每一状态转移过来的方法,然后递归还原插入到相应的位置,最后输出。
注意:此题有个巨坑,最后一组测试数据是空行(没错,输入的字符串<=100)。ZOJ是把多个数据集合在一组里,读入字符串不能用scanf,要用gets。POJ是单组数据测,就随意了。
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <vector>
#define OP(s) cout<<#s<<"="<<s<<" ";
#define PP(s) cout<<#s<<"="<<s<<endl;
using namespace std;
char a[110];
int path[110][110];
vector<char> pre[110],next[110];
inline char kh(char s)
{
switch (s)
{
case '(' :
return ')';
case ')' :
return '(';
case '[' :
return ']';
case ']' :
return '[';
}
}
void find(int l,int r)
{
if (l > r) return ;
int m = path[l][r];
if (m == -1)
{
next[r].push_back(kh(a[l]));
find(l+1,r);
}
if (m == -2)
{
pre[l].push_back(kh(a[r]));
find(l,r-1);
}
if (m == -3) find(l+1,r-1);
if (m > 0) find(l,m),find(m+1,r);
}
int main()
{
freopen("test.txt","r",stdin);
int T;
scanf("%d",&T);
getchar();
for (int cas = 0; cas < T; cas++)
{
if (cas) cout<<endl;
//scanf("%s",&a[1]);
getchar();
gets(a);
int len = strlen(a);
for (int i = len;i >= 1;i--) a[i] = a[i-1];
a[0] = '#';
a[len+1] = 0;
static int f[110][110];
memset(path,0,sizeof(path));
memset(f,0,sizeof(f));
for (int i = 1; i <= len; i++)
{
f[i][i] = 1;
if (a[i] == '[' || a[i] == '(') path[i][i] = -1;
if (a[i] == ']' || a[i] == ')') path[i][i] = -2;
}
for (int k = 1; k <= len-1; k++)
{
for (int i = 1; i <= len; i++)
{
int j = i+k;
if (j > len) break;
f[i][j] = 1<<30;
if ((a[i] == '(' && a[j] == ')' || a[i] == '[' && a[j] == ']') && f[i+1][j-1] < f[i][j]) f[i][j] = f[i+1][j-1],path[i][j] = -3;
for (int m = i; m < j; m++)
if (f[i][m]+f[m+1][j] < f[i][j]) f[i][j] = f[i][m] + f[m+1][j],path[i][j] = m;
if (a[i] == '(' || a[i] == '[') if (f[i+1][j] + 1 < f[i][j]) f[i][j] = f[i+1][j] +1,path[i][j] = -1;
if (a[j] == ')' || a[j] == ']') if (f[i][j-1] + 1 < f[i][j]) f[i][j] = f[i][j-1]+1,path[i][j] = -2;
}
}
for (int i = 0; i <= 109; i++)
pre[i].clear(),next[i].clear();
find(1,len);
for (int i = 1; i <= len; i++)
{
int size = next[i-1].size();
for (int j = size - 1; j >= 0; j--) printf("%c",next[i-1][j]);
size = pre[i].size();
for (int j = 0; j < size; j++) printf("%c",pre[i][j]);
printf("%c",a[i]);
}
int size = next[len].size();
for (int j = size-1; j >= 0; j--) printf("%c",next[len][j]);
cout<<endl;
}
return 0;
}