LightOJ1422-区间dp

题目链接:https://vjudge.net/contest/289043#problem/A
ps: LightOJ - 1422我进不去555

Description
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

题意
给出t组数据
每组数据给n场聚会,之后的第i个数为第i场宴会需要穿什么衣服,衣服可以一件套一件的穿,但脱下的衣服即作废,每场宴会需要露出对应编号的衣服在最外层。求最少需要穿几件衣服。

思路
真正意义上第一道区间dp。
设dp[i][j],为区间[i,j]时最少需要穿几件衣服。
第一种解法是先遍历区间长度,再遍历区间起点。令j=i+区间长度-1,简单来说,遍历到dp[i][j]的时候dp[i+1][j]已经确定了,则可以初始化dp[i][j]=dp[i+1][j]+1,意思为区间[i+1,j]之前先穿一件衣服。
但是这并不是最优的答案,因为有可能这件衣服的编号在[i+1,j]中出现过。所以我们遍历区间[i+1,j],设点k与点i的编号相同,这时就有一种可能,这件衣服从点i穿上,一直穿到点k,则我们要比较dp[i+1][k]+dp[k+1][j](此处的dp[i+1][k]意为点i的衣服穿到点k所以只会在点k计算一次),和当前dp[i][j]哪种方法更优。

但这时候我们也会发现dp[i][j-1]也是确定的,所以我们可以吧dp[i][j]初始化为dp[i][j-1]+1。然后在[i,j-1]区间内找点k与点j相同,一样的思考方式,这两种写法都可以过。

然后是第二种方式,虽然大同小异(笑
先反向遍历区间起点,然后正向遍历区间终点(或者先正向遍历终点,再反向遍历起点)。
这种做法其实和第一种非常相似,如果先起点再终点,则每次dp[i][j]时dp[i+1][j]都是已知的,则变成了上面的做法,而先终点再起点则每次dp[i][j-1]都是已知的。

所以这道题我过了四次…
下面给出了2种方法,可以延伸完成另外两种。

先遍历区间长度的做法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
typedef long long ll;
const int INF = 2e9;
const int mod = 1000000007;
int a[110];
int dp[110][110];
int main() {
int t;
cin >> t;
int cnt = 1;
while (t--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
memset(dp, 0, sizeof(dp));
for (int len = 1; 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+1][k] + dp[k+1][j]);
}
}
}
}
printf("Case %d: %d\n", cnt++, dp[1][n]);
}
}

先反向遍历区间起点,然后正向遍历区间终点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
typedef long long ll;
const int INF = 2e9;
const int mod = 1000000007;
int a[110];
int dp[110][110];
int main() {
int t;
cin >> t;
int cnt = 1;
while (t--) {
int n;
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", cnt++, dp[1][n]);
}
}

谢谢你请我吃糖果

你可能感兴趣的:(LightOJ1422-区间dp)