Poj1411:Brackets Sequence 网络主流方法的一个小问题

来源:互联网 发布:python中str和string 编辑:程序博客网 时间:2024/05/18 22:52

题目源址:点击打开链接

解这道题有多种思路,我具体用的是一个自下而上的由最小子问题解决的方法。具体的算法请参考此博客:http://m.blog.csdn.net/blog/maverick1990/8780123;解题思路大致的意思是:dp[i][j]表示[i,j]间最少需添加几个字符才能合理,初始dp[i][i]=1,dp[i][j>i]=max,dp[i][j<i]=0,按j-i的长度由短到长遍历,若i,j为对应的左右括号,dp[i][j]=dp[i+1][j-1],否则dp[i][j]=min(dp[i][k],dp[k+1][j]),i<=k<j,value[i][j]记录中间转接点k,用来输出结果。这里记录和输出结果的方法大同小异,但是按照这种方法实现的代码我提交上去是WA,我找到了题目的所有数据测试了一下,发现形如“【】【】”和“()()”的结果是“【【】【】】”和“(()())”。我用这个数据人工按照算法跑了一便发现最后算出来的整个段需要插入值为2,其实应该为0。后来分析一下是状态方程没有完全正确。

原解题报告可以理解为这样:

if i,j为对应左右括号:

dp[i][j]=dp[i+1][j-1]

else

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

这个状态转换方程的错误在于,如果两边括号是配对的,直接取其内字段的DP值,但是有可能这个值是比min(dp[i][k],dp[k+1][j])大的,就如【】【】的情况。

如果,按照上面的转换dp[0][3] = 2; 但是dp[0][1] + dp[2][3] = 0而dp[0][3]应该为0。所以正确的状态转换方程应该如下:

if i,j为对应左右括号:

dp[i][j]= MIN(dp[i+1][j-1],min(dp[i][k] + dp[k+1][j]));

else

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

按照这种思路改变过后,提交的代码也是可以通过了。下面贴上我写的源码:

#include <iostream>
#include <string>
using namespace std;


//global strcture
const int MAX_INT = 200;
int dp[101][101];
int value[101][101];
string source;


bool Is_Compare(char c1, char c2);
bool Compare(char c, char &dest);
int FindMinmum(int i, int j);
void print(int i, int j);


int main()
{


// freopen("sample.txt","r",stdin);
while(getline(cin, source))
{
int length = source.size();
//init
for(int i = 0; i < length; i++)
{
for(int j = 0; j < length; j++)
{
value[i][j] = 0;
if(i < j)
dp[i][j] = MAX_INT;
else if(i > j)
dp[i][j] = 0;
else
dp[i][j] = 1;
}
}


//do caculate
for(int step = 1; step < length; step++)
{
for(int i = 0; i + step < length; i++)
{
int j = i + step;
if(Is_Compare(source[i], source[j]))
{
dp[i][j] = dp[i + 1][j - 1];
int temp = FindMinmum(i, j);
if(temp < dp[i][j])
{
dp[i][j] = temp;
}
else
value[i][j] = -1;
}
else
dp[i][j] = FindMinmum(i, j);
}
}


//output
print(0, length - 1);
cout << endl;
}
return 0;
}


bool Is_Compare(char c1, char c2)
{
if((c1 == '(' && c2 == ')') || (c1 == '[' && c2 == ']'))
return true;
else return false;
}


bool Compare(char c, char &dest)
{
if(c == '(')
{
dest = ')';
return true;
}
else if(c == ')')
{
dest = '(';
return false;
}else if(c == '[')
{
dest = ']';
return true;
}else{
dest = '[';
return false;
}
}


int FindMinmum(int i, int j)
{
int min_value = MAX_INT;
for(int k = i; k < j; k++)
{
int temp = dp[i][k] + dp[k + 1][j];
if(temp < min_value)
{
min_value = temp;
value[i][j] = k;
}

}
return min_value;
}


void print(int i, int j)
{
if(i > j)
return;
if(i == j)
{
if(source[i] == '(' || source[i] == ')')
cout << "()";
else cout << "[]";
return;
}
if(value[i][j] == -1)
{
cout << source[i];
print(i + 1, j - 1);
cout << source[j];
return;
}
int k = value[i][j];
print(i, k);
print(k+1, j);
}