zoukankan      html  css  js  c++  java
  • CF293B Distinct Paths 搜索

    CF293B Distinct Paths

    搜索。

    LG传送门

    看数据范围(n,m)显然是不可能到(1000)的,可以知道当(n + m - 1 > k)时无解。一下就把数据范围降到(10)

    考虑枚举每个点的颜色,每个位置的颜色不能和它左边和上方的颜色相同,现在需要快速计算填每种颜色的方案数,到这里分出了两种写法。

    一种是对于每种没有使用过的颜色都只算一次,像下面这样:

    #include <cstdio>
    #include <cctype>
    #define R register
    #define I inline
    #define B 1000000
    using namespace std;
    const int N = 13, M = 10003, yyb = 1e9 + 7;
    char buf[B], *p1, *p2;
    I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
    I int rd() {
        R int f = 0;
        R char c = gc();
        while (c < 48 || c > 57)
            c = gc();
        while (c > 47 && c < 58)
            f = f * 10 + (c ^ 48), c = gc();
        return f;
    }
    int lg[M], col[N][N], f[N][N], use[N], n, m, k;
    int dfs(int x, int y) {
        if (y > m)
            ++x, y = 1;
        if (x > n)
            return 1;
        R int fir = -1, tmp, now = f[x][y - 1] | f[x - 1][y], o = 0, i;
        for (i = (~now) & ((1 << k) - 1); i; i ^= i & -i) {
            tmp = lg[i & -i];
            if (col[x][y] == 0 || col[x][y] == tmp) {
                ++use[tmp], f[x][y] = now | (1 << tmp - 1);
                if (use[tmp] == 1) {
                    if (fir == -1)
                        fir = dfs(x, y + 1);
                    o += fir;
                }
                else
                    o += dfs(x, y + 1);
                o %= yyb, --use[tmp];
            }
        }
        return o;
    }
    int main() {
        R int i, j;
        n = rd(), m = rd(), k = rd();
        if (n + m - 1 > k) {
            printf("0");
            return 0;
        }
        for (i = 1; i <= n; ++i)
            for (j = 1; j <= m; ++j)
                col[i][j] = rd(), ++use[col[i][j]];
        for (i = 1, j = 1; j <= k ; i <<= 1, ++j)
            lg[i] = j;
        printf("%d", dfs(1, 1));
        return 0;
    }
    
    

    一种是处理出用了多少种本来没有使用过的颜色,设总的没有使用过的颜色是(y)个,用了(x)个,计算贡献的时候就乘个(P _ y ^ x),即在(y)种颜色中选(x)个排到需要用的(x)个地方,像下面这样:

    #include <cstdio>
    #include <cctype>
    #define R register
    #define I inline
    #define B 1000000
    using namespace std;
    const int N = 13, yyb = 1e9 + 7;
    char buf[B], *p1, *p2;
    I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
    I int rd() {
        R int f = 0;
        R char c = gc();
        while (c < 48 || c > 57)
            c = gc();
        while (c > 47 && c < 58)
            f = f * 10 + (c ^ 48), c = gc();
        return f;
    }
    int a[N][N], b[N], f[N], p, n, m, k, ans;
    void dfs(int x, int y, int q) {
        if (y > m)
            return dfs(x + 1, 1, q);
        if (x > n) {
            ans = (ans + f[p] / f[p - q]) % yyb;
            return ;
        }
        if (a[x][y])
            return dfs(x, y + 1, q);
        R int c[N], i, j, t;
        for (i = 1; i <= k; ++i)
            c[i] = 0;
        for (i = 1; i <= x; ++i)
            for (j = 1; j <= y; ++j)
                c[a[i][j]] = 1;
        for (i = x; i <= n; ++i)
            for (j = y; j <= m; ++j)
                c[a[i][j]] = 1;
        for (i = 1, j = 0, t = 0; i <= k; ++i) {
            if (b[i] ^ 1)
                ++j;
            if ((!c[i]) && ((b[i] == 1) || (j <= q + 1))) {
                if ((!b[i]) && (j == q + 1))
                    t = 1, b[i] = 2;
                a[x][y] = i, dfs(x, y + 1, q + t);
                if (t)
                    b[i] = 0, t = 0;
            }
        }
        a[x][y] = 0;
    }
    int main() {
        n = rd(), m = rd(), k = rd();
        if (n + m - 1 > k) {
            printf("0");
            return 0;
        }
        R int i, j, x, y;
        for (i = 1; i <= n; ++i)
            for (j = 1; j <= m; ++j)
                a[i][j] = rd();
        for (i = 1; i <= n; ++i)
            for (j = 1; j <= m; ++j)
                if (a[i][j]) {
                    b[a[i][j]] = 1;
                    for (x = i; x <= n; ++x)
                        for (y = j; y <= m; ++y)
                            if (((i ^ x) || (j ^ y)) && a[i][j] == a[x][y]) {
                                printf("0");
                                return 0;
                            }
                }
        f[0] = 1;
        for (i = 1; i <= k; ++i)
            p += (!b[i]), f[i] = f[i - 1] * i;
        dfs(1, 1, 0), printf("%d", ans);
        return 0;
    }
    
    

    事实上,这两种剪枝的依据都是:没有用到过的颜色对于搜索状态的影响是一样的,从而减少了重复计算。

  • 相关阅读:
    centos 7.0.1406 临时环境jenkins安装
    jenkins 登录提示无效
    ubuntu 16.04 安装完QQ后,更新或apt-get报错
    Web服务网站故障分析常用的命令
    在CentOS7中给docker加权限
    aliyun阿里云Maven仓库地址和其他地址
    python 安装 docker-copmose
    mysql 1055错误
    linux 添加用户
    firewall 开启服务
  • 原文地址:https://www.cnblogs.com/cj-chd/p/10302991.html
Copyright © 2011-2022 走看看