POJ 1141 Brackets Sequence(구간 DP)

2263 단어 구간DP

이것은 아주 좋은 구간 DP문제로 하나의 서열에 물건을 삽입하는 것과 같은 문제는 모두 중간에서 두 개의 이 방향을 나누어 고려할 수 있다.
dp[i][j]는 i에서 j까지의 단락에 최소한 괄호를 삽입해야 하는 수량을 나타낸다. 분명히 이 수는min(dp[i][k], dp[k+1][j])와 같다. 그 중에서 0<=kn3자 순환, 매거 구간 길이, 기점, 구분점, 마지막으로 양쪽이 일치하는 특수한 상황을 판단한다.
이 문제는 문자열을 복원하고 귀속적인 방법으로 print(a, b)이라는 함수로 a에서 b 구간의 상황을 출력하고 각 구간이 선택한 가장 좋은 구분점이 무엇인지, 그리고 가장 좌우 양쪽이 일치하도록 선택했는지 기록한다.그리고 출력을 되돌려줍니다. a==b일 때 s[a]가 (또는) 출력하고 반대로 출력합니다.
빈 줄 입력이 있는 경우scanf("%[^]s",str)로 입력하십시오
코드:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#include <string>
#include <map>
#define INF 1000000
int dp[105][105];
int path[105][105];
char s[105];
bool mat[105][105];

bool match(char a,char b){
	return a=='['&&b==']'||a=='('&&b==')';
}

void print(int a,int b){
	if(a>b) return ;
	if(a==b){
		if(s[a]=='('||s[a]==')') printf("()");
		else printf("[]");
	}

	else if(mat[a][b]){
		printf("%c",s[a]);
		print(a+1,b-1);
		printf("%c",s[b]);
	}
	else {
		print(a,path[a][b]);
		print(path[a][b]+1,b);
	}
}

int main(){
	scanf("%[^
]s",s); int len=strlen(s); if(len==0){ printf("
"); } else{ for(int i=0;i<len;i++){ dp[i][i]=1; } for(int i=0;i<len-1;i++){ if(match(s[i],s[i+1])){ dp[i][i+1]=0; mat[i][i+1]=1; } else{ dp[i][i+1]=2; path[i][i+1]=i; } } for(int i=3;i<=len;i++){ for(int j=0;j<len-i+1;j++){ dp[j][j+i-1]=INF; int ist=0; for(int k=j;k<j+i-1;k++){ if(dp[j][k]+dp[k+1][j+i-1]<dp[j][j+i-1]){ dp[j][j+i-1]=dp[j][k]+dp[k+1][j+i-1]; ist=k; } } if(match(s[j],s[j+i-1])){ if(dp[j+1][j+i-2]<dp[j][j+i-1]){ mat[j][j+i-1]=1; dp[j][j+i-1]=dp[j+1][j+i-2]; } } path[j][j+i-1]=ist; } } print(0,len-1); printf("
"); } return 0; }

좋은 웹페이지 즐겨찾기