LightOJ - 1422 Halloween Costumes

思路

题意是一个人要参加不同的晚会需要穿不同的衣服,衣服可以意见套一件然后再反序脱掉,问最少需要多少件衣服。容易想到使用区间dp。一开始想的状态转移方程是当两端不匹配时,dp[l][r]=min(dp[l+1][r],dp[l][r-1])+1。当两端匹配时,dp[l][r]=dp[l+1][r-1]+1。一开始还觉得没问题,结果得了WA。发现不能只考虑两端的复用,要考虑第一件衣服和中间某件(假设为k)的复用,因为有可能在中间复用会使得dp[l][r]更小。
状态转移方程:
对于两端不匹配的情况:dp[l][r]=min(dp[l+1][r],dp[l][r-1])+1;
对于l-r范围中我们枚举k,如果cloth[l]==cloth[k],代表我们考虑中间第k件复用:dp[l][r]=min(dp[l][r],dp[l][k-1]+dp[k+1][r]);

代码

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
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <functional>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cctype>
#include <sstream>
#include <complex>
#define INF 1e9
#define ll long long
#define ull unsigned long long
#define ms(a,val) memset(a,val,sizeof(a))
#define lowbit(x) ((x)&(-x))
#define lson(x) (x<<1)
#define rson(x) (x<<1+1)
#define sqr(x) ((x)*(x))

using namespace std;
int dp[105][105],a[105];
int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t,n;
cin >> t;
for(int z=0;z<t;z++) {
ms(dp, 0);
cin >> n;
for (int i = 0;i < n;i++) {
cin >> a[i];
dp[i][i] = 1;
}
for (int len = 2;len <= n;len++) {
for (int l = 0;l + len - 1 < n;l++) {
int r = l + len - 1;
dp[l][r] = min(dp[l][r-1],dp[l + 1][r]) + 1;
for (int k = l + 1;k <= r;k++) {
if (a[l] == a[k]) {
dp[l][r] = min(dp[l][r], dp[l][k - 1] + dp[k + 1][r]);
}
}
}
}
cout << "Case "<<z+1<<": "<<dp[0][n - 1] << "\n";
}
return 0;
}