zoukankan      html  css  js  c++  java
  • [BZOJ]2220 Zuma2

    祖玛游戏,两种颜色的球,每次可以选定一个长度为$k$的区间,区间内球同色,消除这个区间。消除后左右两边合并,但不会继续消除。求最小操作次数。

    考虑对于一个区间,最后一个消灭的肯定是最左边的一些同色球。

    为什么是这样?

    首先如果只有这个区间,那么最左边永远可以指定作为最后一次消除:因为消除它不会对右边产生影响。

    可能想不到的是,如果先消除左端点,右边就能跟区间外的合并,这样是不是不优了?

    答案是否定的:先消除左端点,把右边合并到左边区间,可以把左端点这一段划到左边区间去,那么还是相当于右边成为了新的左端点。

    那么$f[i][j][k]$表示$i,j$区间,消完剩余$k$个与左端点同色的,需要的次数。

    $g[i][j]$表示消完$i,j$区间,需要的次数。

    转移方程:

    $f[i][j][k] = min{f[i][x][k] + g[k+1][j]}$

    当$a[i]==a[j]$时有额外转移:$f[i][j][k]=min{f[i][j-1][k-1]}$

    对于$g$数组,$g[i][j] = min{f[i][j][k]+1, g[i][x]+f[x+1][j]}$

    代码如下:

    #include <bits/stdc++.h>
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    int n, k, f[109][109][109], g[109][109], sum1[109], sum2[209];
    char c[109];
    signed main()
    {
        n = read(); k = read();
        scanf("%s", c + 1);
        memset(f, 0x3f, sizeof(f));
        memset(g, 0x3f, sizeof(g));
        for(int i = 1; i <= n; i++) {
            sum1[i] = sum1[i - 1] + c[i] == 'G';
            sum2[i] = sum2[i - 1] + c[i] == 'H';
        }
    /*
        for(int i = 1; i <= n; i++) 
            for(int j = i; j <= n; j++)
                if(sum1[j] - sum1[i - 1] == 0 || sum2[j] - sum2[i - 1] == 0)
                    g[i][j] = 1;
    */
        for(int i = 1; i <= n; i++)
            f[i][i][1] = 0;
        for(int len = 1; len <= n; len++) {
            for(int i = 1; i + len - 1 <= n; i++) {
                int j = i + len - 1;
                for(int q = 1; q <= len; q++) {
                    for(int p = i; p + 1 <= i + len - 1; p++) {
                        f[i][j][q] = min(f[i][j][q], f[i][p][q] + g[p + 1][j]);
                    }
                    if(c[i] == c[i + len - 1] && q > 1 && j - 1 >= i)
                        f[i][j][q] = min(f[i][j][q], f[i][j - 1][q - 1]);
                    if(q >= k)
                        g[i][j] = min(g[i][j], f[i][j][q] + 1);
                }
            }
            for(int i = 1, j = i + len - 1; i + len - 1 <= n; i++) 
                for(int p = i; p + 1 <= i + len - 1; p++)
                    g[i][j] = min(g[i][j], g[i][p] + g[p + 1][j]);
        }
        printf("%d
    ", g[1][n] == 0x3f3f3f3f ? -1 : g[1][n]);
        return 0;
    }
    View Code
  • 相关阅读:
    hadoop 动态调整mapred参数
    python 遍历hadoop, 跟指定列表对比 包含列表中值的取出。
    replay的意义
    c++ 异常 warning: 'MEMORY_UNIT_NAME' defined but not used
    c++ 异常 discards qualifiers 丢弃
    c++ 条件变量
    声明
    HibernateSessionFactory建立-使用ThreadLocal
    App Crawler使用教程
    loadrunner生成随机数用于Action参数中
  • 原文地址:https://www.cnblogs.com/onglublog/p/14375574.html
Copyright © 2011-2022 走看看