给一个序列,每次操作可以取出一个回文串,两侧的数字会向中间合并。
问最少操作次数。
区间dp,
f
[
i
]
[
j
]
f[i][j]
f[i][j]代表取完区间
[
i
,
j
]
[i,j]
[i,j]的操作次数。
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
]
[
k
]
+
f
[
k
+
1
]
[
j
]
)
f[i][j]=min(f[i][k]+f[k+1][j])
f[i][j]=min(f[i][k]+f[k+1][j])。
a
[
i
]
=
=
a
[
j
]
a[i]==a[j]
a[i]==a[j]时,
f
[
i
]
[
j
]
=
f
[
i
+
1
]
[
j
−
1
]
f[i][j]=f[i+1][j-1]
f[i][j]=f[i+1][j−1],即
a
[
i
]
,
a
[
j
]
a[i],a[j]
a[i],a[j]均可以合并到
[
i
+
1
,
j
−
1
]
[i+1,j-1]
[i+1,j−1]区间的某一个回文串中。
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define maxn 500
int n;
int a[maxn+5];
int f[maxn+5][maxn+5];
int main() {
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) f[i][i]=1;
for(int i=1;i<n;i++) {
if(a[i]==a[i+1]) f[i][i+1]=1;
else f[i][i+1]=2;
}
for(int j=3;j<=n;j++) {
for(int i=j-2;i>=1;i--) {
f[i][j]=(1<<30);
if(a[i]==a[j]) f[i][j]=f[i+1][j-1];
for(int k=i;k<j;k++) {
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
printf("%d",f[1][n]);
return 0;
}