题目大意:
一个人去参加晚会,不同的晚会要穿不同的衣服,他一次性可以穿几件衣服,但是衣服一旦脱下来就变成旧衣服了,他就不会再穿了,问他参加n个晚会,至少要穿几件衣服。
题解:
这个题目可以转化成涂色问题,每一次可以连续涂若干长度的颜色,问最少涂多少次颜色,使得这个序列变成我们想要的颜色。
\(dp[i][j]\) 表示从 \(i\) 到 \(j\) 最少涂 \(dp[i][j]\) 次颜色。
这个转移方程怎么写呢?可以以左端点作为判断的依据。
对于一个区间 \([l,r]\) 假设最先从左端点开始涂颜色,如果这个区间还有和左端点的颜色是一样的,那么则说明这个点就是最开始已经涂过了,所以以这个点为分节符,从这个点的两边转移过来。
\(dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j])\)
#include <bits/stdc++.h>
#define id first
#define val second
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=110;
typedef long long ll;
int dp[maxn][maxn],a[maxn];
int main(){
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
int n;
scanf("%d",&n);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) scanf("%d",&a[i]),dp[i][i]=1;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
dp[i][j]=dp[i+1][j]+1;
for(int k=i+1;k<=j;k++){
if(a[k]==a[i]) dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]);
}
}
}
printf("Case %d: %d\n",cas,dp[1][n]);
}
return 0;
}