SPOJ6340 ZUMA - ZUMA

题意:n个珠子排成一排,都有各自的颜色。

你可以选择不少于w个连续同色的珠子消掉,也可以先放着。你还可以任意插入任意颜色的珠子。

求全部消掉至少要插入几个珠子。

解:

什么毒瘤东西......

有个十分难受的DP。状态表示是f[l][r][k]表示在[l, r]这一段,l的左边有额外的k个与l同色的珠子时,把它们全部消去的最少代价。

转移也过于毒瘤。首先有

if k == w - 1
  f[l][r][k] = f[l + 1][r][0] 
else
    f[l][r][k] = f[l][r][k + 1] + 1

然后然后还要考虑两段拼起来的情况,就是我们从中间选一段消去。

if(color i == l) 
    f[l][r][k] = f[l + 1][i - 1][0] + f[i][r][k + 1] 

这样我们就可以保证正确性了。写成记忆化搜索不用考虑转移顺序。代码十分之短.....

需要注意的是不能把相连的一段同色珠子合并,这样不一定是最优解。(??)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 const int N = 110, INF = 0x3f3f3f3f;
 6 
 7 int f[N][N][N], n, a[N], w; 
 8 int sum[N], col[N], top;
 9 
10 int solve(int l, int r, int k) {
11     //printf("%d %d %d \n", l, r, k);
12     if(f[l][r][k] != -1) {
13         return f[l][r][k];
14     }
15     if(r < l) {
16         return 0;
17     }
18     
19     int ans = INF;
20     if(k + 1 >= w) {
21         ans = solve(l + 1, r, 0);
22     }
23     else {
24         ans = solve(l, r, k + 1) + 1;
25     }
26     for(int i = l + 1; i <= r; i++) { 
27         if(col[l] == col[i]) { // [l + 1, i - 1]  [i, r] 
28             ans = std::min(ans, solve(l + 1, i - 1, 0) + solve(i, r, k + 1)); 
29         }
30     }
31     return f[l][r][k] = ans;
32 }
33 
34 int main() {
35     memset(f, -1, sizeof(f));
36     scanf("%d%d", &n, &w);
37     for(int i = 1; i <= n; i++) {
38         scanf("%d", &col[i]);
39     }
40     
41     int ans = solve(1, n, 0); 
42     printf("%d", ans);
43     
44     return 0;
45 }
AC代码

除此之外还有两种四维状态的DP,一种是f[l][r][k][a]表示把l到r这一段区间消除至只剩a(左/右)端的k个珠子的最小代价。

还有一种是f[l][r][k][s]表示把l到r这一段区间消除至只剩k个s颜色的珠子的最小代价。

写起来比较长,但是应该是比正解好想很多的。我没写,就不贴代码了。

posted @ 2018-11-01 07:54  huyufeifei  阅读(186)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜