Halloween Costumes LightOJ - 1422(区间dp)

Halloween Costumes LightOJ - 1422

Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is planning to attend as many parties as he can. Since it's Halloween, these parties are all costume parties, Gappu always selects his costumes in such a way that it blends with his friends, that is, when he is attending the party, arranged by his comic-book-fan friends, he will go with the costume of Superman, but when the party is arranged contest-buddies, he would go with the costume of 'Chinese Postman'.

Since he is going to attend a number of parties on the Halloween night, and wear costumes accordingly, he will be changing his costumes a number of times. So, to make things a little easier, he may put on costumes one over another (that is he may wear the uniform for the postman, over the superman costume). Before each party he can take off some of the costumes, or wear a new one. That is, if he is wearing the Postman uniform over the Superman costume, and wants to go to a party in Superman costume, he can take off the Postman uniform, or he can wear a new Superman uniform. But, keep in mind that, Gappu doesn't like to wear dresses without cleaning them first, so, after taking off the Postman uniform, he cannot use that again in the Halloween night, if he needs the Postman costume again, he will have to use a new one. He can take off any number of costumes, and if he takes off k of the costumes, that will be the last k ones (e.g. if he wears costume A before costume B, to take off A, first he has to remove B).

Given the parties and the costumes, find the minimum number of costumes Gappu will need in the Halloween night.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing an integer N (1 ≤ N ≤ 100) denoting the number of parties. Next line contains N integers, where the ith integer ci (1 ≤ ci ≤ 100) denotes the costume he will be wearing in party i. He will attend party 1 first, then party 2, and so on.

Output

For each case, print the case number and the minimum number of required costumes.

Sample Input

2

4

1 2 1 2

7

1 2 1 1 3 2 1

Sample Output

Case 1: 3

Case 2: 4

题意:

万圣节到了,有N个party,对于每一个party,都要穿一种服装,服装可以套着穿,但是脱了的不能再用,参加party必须按顺序来,从第一个到第N个,问参加这些party最少需要几件服装

分析:

dp[i][j]代表从区间i到区间j最少的穿衣数量

因为从前往后看的话每一个状态都可能影响后面的状态,这样需要我们从后往前递推

那么在dp[i][j]这个状态的穿衣数就分为下面两种情况:

1) 如果在i位置我新穿上a[i]这件衣服的话,那么很明显这时

d p [ i ] [ j ] = d p [ i + 1 ] [ j ] + 1

也就是后面的最少需要的衣服数量加上这一件

2)如果我在[i+1,j] 区间当中能够找到一个party所需要的衣服和i位置需要的衣服相同,那么在i位置我可以不用新穿一件a[i]衣服,那当前的衣服数应该是多少呢?

我们有 d p [ i ] [ j ] = d p [ i + 1 ] [ k 1 ] + d p [ k ] [ j ]

什么意思呢?

我们就假设k处需要的衣服和i处相同,这样我可以把k处衣服穿在最外面,这样同样就可以参加i party了,然后里面套着的是k之后的衣服,然后参加完i party后,参加i+1,i+2…,这样就是两部分加起来之和为最小数量

因此状态转移方程为

d p [ i ] [ j ] = m i n ( d p [ i + 1 ] [ j ] + 1 , d p [ i + 1 ] [ k 1 ] + d p [ k ] [ j ] )

code:

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

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/81352079