LightOJ 1422 Halloween Costumes

原題:
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 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.

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

樣例輸入

2

4

1 2 1 2

7

1 2 1 1 3 2 1

輸出

Case 1: 3
Case 2: 4

中文:

你要參加一串舞會,參加不同的舞會需要穿不同的禮服,你穿禮服可以像套娃一樣,外面套好多層,不過脫下來的衣服就不能再穿上了,問你最少穿多少衣服可以參加所以的舞會。

代碼:

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;

typedef pair<int,int> pii;
const int maxn = 105;
int a[maxn];
int dp[maxn][maxn];
int n;

int dfs(int i,int j)
{
    if(j<i)
        return 0;
    if(i==j)
    {
        dp[i][j]=1;
        return 1;
    }
    if(dp[i][j]>0)
        return dp[i][j];
    dp[i][j]=dfs(i,j-1)+1;
    for(int k=i;k<j;k++)
    {
        if(a[k]==a[j])
            dp[i][j]=min(dp[i][j],dfs(i,k)+dfs(k+1,j-1));
    }
    return dp[i][j];
}
int t;
int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    int k =0;
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        int ans = dfs(1,n);
        cout<<"Case "<<++k<<": "<<ans<<endl;
    }
    return 0;
}

思路:

kuangbing大神的區間dp練習場,說啥也沒看出這題怎麼用區間的關係來描述狀態。不得不說匡神的題目質量還真是高。

既然都說是區間dp了,肯定是用兩個下標來描述一段區間的狀態

設置dp[i][j]dp[i][j]表示參加第i場舞會到第j場舞會所需要帶的最少衣服

此題容易給人一種錯覺,由於參加舞會是第一個到最後一個依次參加,很容易讓人想到DAG模型,如果使用區間模型,那麼如何保證當前描述的區間狀態的最優解,是不受到序列順序的影響呢?

一般的區間dp,考慮決策方向都是可以從兩個方向考慮的,即下標i和下標j,這也是一個思維誤區,認爲區間動態規劃的狀態轉移,需要能給夠在兩個方向上進行。其實不是這樣, 區間dp也同樣只可以在同一個方向上進行狀態轉移,以上一個區間作爲候選狀態,向前遞推。

那麼本題目的狀態轉移方程可以表示爲

如果參加第j個舞會,選擇直接穿上一件第j個舞會要求的禮服
dp[i][j]=min(dp[i][j],dp[i][j1]+1)dp[i][j]=min(dp[i][j],dp[i][j-1]+1)

如果採用“套娃”式穿衣策略,此時枚舉區間[i,j]中你參加過的第k個舞會,要求穿的禮服與第j個舞會的禮服相同,你可以在參加第j個舞會時,把參加[k+1,j-1]的舞會時的衣服脫掉
注意,此時的狀態不應該是dp[i][j]=min(dp[i][j],dp[i][k])dp[i][j]=min(dp[i][j],dp[i][k])
而是
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j1])dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j-1])
因爲你參加[k+1,j-1]個舞會的時候也要穿禮服,這也是爲什麼要用區間模型的原因

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章