zjnu(1183)——括號序列【基礎演算法・動態規劃】——高階
首先,我只想宣告一點,這道題有毒。。。我用char讀入就錯了,然而換成string讀入就對了或者可以把定義char的陣列開的大一點,原先1A的一題硬是糾結了老半天。
傳送門:zjnu
題意:
就是對於一個組成的序列,新增儘量少的括號得到一個規則序列,並且輸出這個序列的長度。
不過我學到了兩種定義dp狀態的方法:
1)定義dp[i][j]為i~j中需要新增的最少的括號數。這裡我們記錄s為一段字元的開始位置,e為一段字元的結束位置。
①當(a[s]=='('&&a[e]==')')||(a[s]=='['&&a[e]==']')時,dp[s][e]=min(dp[s][e],dp[s+1][e-1]);
②當(a[s]=='('&&a[e]!=')')||(a[s]=='['&&a[e]!=']')時,dp[s][e]=min(dp[s][e],dp[s][e-1]+1);
③當(a[e]==')'&&a[s]!='(')||(a[e]==']'&&a[s]!='[')時,dp[s][e]=min(dp[s][e],dp[s+1][e]+1);
④然後當兩個數中間還有其他數存在的時候,那麼我們就用for,像石子歸併那樣,然後去更新dp[s][e]
最後輸出的時候只要輸出dp[0][len-1]+len就好了。
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<cstring> using namespace std; #define inf 99999999 #define maxn 111 int main(){ string a; cin>>a; int l=a.length(); int dp[111][111]; for(int i=0;i<l;i++) dp[i][i]=1; for(int len=2;len<=l;len++){ for(int s=0;s<=l-len;s++){ int e=s+len-1; dp[s][e]=inf;//!!! if((a[s]=='('&&a[e]==')')||(a[s]=='['&&a[e]==']')) dp[s][e]=min(dp[s][e],dp[s+1][e-1]); if((a[s]=='('&&a[e]!=')')||(a[s]=='['&&a[e]!=']')) dp[s][e]=min(dp[s][e],dp[s][e-1]+1); if((a[e]==')'&&a[s]!='(')||(a[e]==']'&&a[s]!='[')) dp[s][e]=min(dp[s][e],dp[s+1][e]+1); for(int k=s;k<e;k++){ dp[s][e]=min(dp[s][e],dp[s][k]+dp[k+1][e]); } } } printf("%d\n",dp[0][l-1]+l); }
2)第二種狀態定義的和第一種有點不一樣。
定義dp[i][j]為i~j的區間內符合規範的字串的最短的長度。
當然在這裡我們需要進行初始化,對於不同位置的dp,我們需要進行不同的計算。(這裡初始化是很重要的)
當a[s]=='('&&a[e]==')'時,那麼dp[s][e]=dp[s+1][e-1]+2;
否則的話,則去尋找跳板,然後更新dp[s][e]。
其實主要的思路就是先算出小區間的每個最短的長度,然後再根據小區間然後去更新大區間的值。
最後輸出的直接是dp[0][len-1]就可以了。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111
#define inf 99999999
int main(){
string a;
cin>>a;
int dp[111][111];
int len=a.length();
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(i==j) dp[i][j]=2;
if(i>j) dp[i][j]=0;
else if(i<j) dp[i][j]=inf;
}
}
for(int l=2;l<=len;l++){
for(int s=0;s<=len-l;s++){
int e=s+l-1;
if((a[s]=='('&&a[e]==')')||(a[s]=='['&&a[e]==']')){
if(l>2) dp[s][e]=dp[s+1][e-1]+2;
else dp[s][e]=2;
}
for(int k=s;k<e;k++){
dp[s][e]=min(dp[s][e],dp[s][k]+dp[k+1][e]);
}
}
}
printf("%d\n",dp[0][len-1]);
}
理解!!!舉一反三!!加油!!!