poj 2955
题意
给你一个括号序列,求最长合法括号序列子串的长度
题解
dp[i][ j]表示区间 i 到 j 之间最长合法括号子串的长度,dp[ i ][ j ] 如果s[i] == s[j],dp[ i ][ j ] = dp[i+1][j-1], 更新最大值的方法是枚举 i 和 j 的中间值,然后让 dp[ i ] [ j ] = max ( dp [ i ] [ j ] , dp [ i ] [ k ] + dp [ k+1 ] [ j ] ) , i <=k <j
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int dp[105][105];
int main()
{
char s[105];
while(scanf("%s",s)){
if(strcmp(s,"end") == 0) break;
memset(dp,0,sizeof dp);
int n = strlen(s);
for(int len = 1 ; len < n;len++){
for(int i = 0,j = len ; j < n ; i++,j++){
if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))
dp[i][j] = dp[i+1][j-1] + 2;
//注意[][]
for(int k = i ; k < j ; k++)
dp[i][j] = max(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
cout << dp[0][n-1] << endl;
}
}
poj1141
题意
给你一个括号序列,给它添加括号让它变成合法括号序列,求最短的合法括号序列并输出
题解
这个题和上面的题相似,多了一个输出,输出是用递归的形式,用一个数组记录每个区间的分界点,dp[i][j] 表示 i 到 j 最少需要添加的括号数
如果是s[i] == s[j] ,dp[i][j] = dp[i+1][j-1],然后遍历分界点,求最小值
输出见代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
int dp[110][110],p[110][110];
char s[110];
void print(int x,int y)
{
if(x > y) return;
if(x == y){
if(s[x] == '(' || s[x] == ')') printf("()");
else printf("[]");
}
else{
if(p[x][y] == -1){
putchar(s[x]);
print(x+1,y-1);
putchar(s[y]);
}
else{
print(x,p[x][y]);
print(p[x][y] + 1 , y);
}
}
}
int main()
{
scanf("%s",s);
int n = strlen(s);
for(int i = 0 ; i < n ; i++) dp[i][i] = 1;
for(int len = 1 ; len < n ; len++){
for(int i = 0 , j = len ; j < n ; i++,j++){
dp[i][j] = INF;
if((s[i] == '(' && s[j] == ')') || (s[i] == '[' && s[j] == ']')){
dp[i][j] = dp[i+1][j-1];
p[i][j] = -1;
}
//为什么不用else,考略[][]情况
for(int k = i ; k < j ; k++)
{
if(dp[i][j] > dp[i][k] + dp[k+1][j]){
dp[i][j] = dp[i][k] + dp[k+1][j];
p[i][j] = k;
}
}
}
}
print(0,n-1);
printf("\n");
return 0;
}