題目大意
給一個長度爲的數組,每次可以把相鄰的兩個相同元素和合併爲,問數組在若干次操作後可以取得的最小長度爲多少?
分析思路
關於這道題目網上已經有了很多題解博客,但是基本上都沒有把分析思路寫的很詳細,於是我寫下這篇博客,記錄一下自己的分析過程。
這個題目的數據範圍爲,所以可以考慮用區間DP搞一下。設爲對應區間能夠經過合併取得的最短長度。首先考慮對任一區間來說,要麼最終可以合併爲1個元素,要麼不能合併爲1個元素。如果不能合併爲1個元素,那麼必然存在一個最優分割點使得如果能合併爲同一個元素,那麼必然存在最優分割點使得而取到這個最優分割點的條件便是此分割點兩側區間均能合併爲同一個值,且它們相等。因此,區間的狀態轉移方程爲其中,表示區間最終合併爲同一個元素的元素值。
AC代碼
#include<bits/stdc++.h>
using namespace std;
const int maxn = 507;
const int MAXINT = 6000000;
int n, dp[maxn][maxn], m[maxn][maxn], a[maxn];
void solve(){
int i, j, k, len;
//初始化
for(i=1;i<=n;++i){
for(j=1;j<=n;++j){
dp[i][j] = MAXINT;
}
dp[i][i] = 1;
m[i][i] = a[i];
}
for(len=2;len<=n;++len){
for(i=1;i<=n-len+1;++i){
j = i + len - 1;
for(k=i;k<=j-1;++k){
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);
if(dp[i][k] == 1 && dp[k+1][j] == 1 && m[i][k] == m[k+1][j]){ //如果可以合併爲一個元素
dp[i][j] = 1;
m[i][j] = m[i][k] + 1;
}
}
}
}
cout<<dp[1][n];
}
int main(){
int t, i, j;
ios::sync_with_stdio(false);
cin>>n;
for(i=1;i<=n;++i) cin>>a[i];
solve();
return 0;
}