题目链接:见这里
解题方法: 区间DP。首先我们把连续相同的珠子都缩在一起 令f[i][j]表示从i开始的j个珠子的最小消除次数 初值 f[i][1]=cnt[i]==1?2:1
然后对于每个区间,我们枚举中间点,拆成两半求和
如果这个区间两端点颜色相同,我们还可以把中间消掉,然后两边再补射1或0个。
但是这个题目数据是有问题的,按照上面的方法是可以AC,但是有反,具体可以参考下这个博客:见这里
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i <= b; i++)
const int inf = 0x3f3f3f3f;
const int N = 550;
pair <int, int> a[N];
int dp[N][N]; //dp[i][j]从i开始的j个珠子的最小消除次数
int n;
int main(){
scanf("%d", &n);
a[0].first = inf;
int cnt = 0;
rep(i, 1, n){
int x;
scanf("%d", &x);
if(x != a[cnt].first){
a[++cnt].first = x;
}
a[cnt].second++;
}
n = cnt;
memset(dp, 0x3f, sizeof(dp));
rep(i, 1, n) dp[i][1] = a[i].second == 1 ? 2 : 1;
rep(j, 2, n){ //区间长度
for(int i = 1; i + j - 1 <= n; i++){ //起点
if(a[i].first == a[i + j - 1].first){
dp[i][j] = dp[i + 1][j - 2] + (a[i].second + a[i + j - 1].second == 2 ? 1 : 0);
}
for(int k = 1; k < j; k++){
dp[i][j] = min(dp[i][j], dp[i][k] + dp[i + k][j - k]);
}
}
}
printf("%d\n", dp[1][n]);
return 0;
}