小灰灰参加圣诞节的一些派对,并且需要穿上对应派对的衣服,所以他需要多次换衣服,为了方便,他可以选择脱掉一些衣服或者穿上新衣服,比如说,他穿着超人的衣服,外面又穿着死侍的衣服,当他要参加超人服装派对时,他可以选择脱掉死侍的衣服(因为死侍衣服的里面有超人的衣服),或者他可以在穿一件超人的衣服,小灰灰是个爱干净的人,当他脱下死侍的衣服后,如果需要再穿死侍的衣服,他会选择再穿一件新的。(如果他先穿A衣服,又穿上B衣服,再穿一件C衣服,如果他想让最外面的衣服是A,他可以选择直接穿一件A,或者先把C脱掉,再把B脱掉)。

输入

第一行输入一个T,表示测试案例的数量 T<=200 N和a[i]<=100
接下来一行输入一个N,表示派对个数,
接下来一行n个数,表示第i个派对他会穿着a[i]的衣服参加这场派对(派对的前后顺序不可调换)

输出

对于每个测试案例,输出“Case i: ”加所需服装的最小数量。

案例输入

2
4
1 2 1 2
7
1 2 1 1 3 2 1

案例输出

Case 1: 3
Case 2: 4

非常基础的区间dp

上一次做这道题是六个月前

最近在回顾区间dp 所以把这道题拿出来重新做一次

第一次看到本题时完全想不通怎样dp

区间dp其实就是一个如何将两个已经确定后的区间合并成一个区间

那么对于本题如果枚举的断点与本区间的开始相同那么我们就可以让该区间花费在合并时--

code:

#include<bits/stdc++.h>
using namespace std;
int dp[105][105];
int a[105];
int main()
{
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        memset(dp,0x3f,sizeof(dp));
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int len=0;len<n;len++)
        {
            for(int i=1;i+len<=n;i++)
            {
                int j=i+len;
                if(len==0) dp[i][j]=1;
                for(int k=i+1;k<=j;k++)
                {
                    dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k][j]-(a[i]==a[k]));
                }
            }
        }
        printf("Case %d: %d\n",cas++,dp[1][n]);
    }
}