zoukankan      html  css  js  c++  java
  • 【10.26校内测试】【状压?DP】【最小生成树?搜索?】

    Solution

    据说正解DP30行???

    然后写了100行的状压DP??

    疯狂特判,一算极限时间复杂度过不了aaa!!

    然而还是过了....QAQ

    所以我定的状态是待转移的位置的前三位,用6位二进制位表示,每2位表示一个位置的状态。然后特判转移就可以了QAQ

    Code

    #include<bits/stdc++.h>
    #define LL long long
    #define mod 1000000007
    #define RG register
    using namespace std;
    
    char fi[1000005];
    int a[1000005];
    LL dp[2][123];
    int len;
    
    int change(char x) {
        if(x == '?')    return 4; 
        if(x == '*')    return 3;
        if(x == '0')    return 0;
        if(x == '1')    return 1;
        if(x == '2')    return 2;
    }
    
    bool check(int s, int i) {
        int pre = s & (3 << 4);
        int s1 = s >> 4, s2 = (s ^ pre) >> 2, s3 = s & 3;
        if(~a[i] && a[i] != 4 && s3 != a[i])    return 0;
        if(i - 1 > 0 && a[i - 1] != 4 && s2 != a[i - 1])    return 0;
        if(i - 2 > 0 && a[i - 2] != 4 && s1 != a[i - 2])    return 0;
        if(i == len) {
            if(s3 == 1 && s2 != 3)    return 0;
            if(s3 == 2)    return 0;
            if(s3 == 3 && s2 == 0)    return 0;
        }
        if(i == 1) {
            if(s1 || s2)    return 0;
            if(s3 == 2)    return 0;
            return 1;
        } else if(i == 2) {
            if(s1)    return 0;
            if(s2 == 0 && s3 == 3)    return 0;
            if(s2 == 1 && s3 != 3)    return 0;
            if(s2 == 2)    return 0;
            if(s2 == 3 && s3 == 0)    return 0;
            if(s3 == 2 && s2 != 3)    return 0;
            return 1;
        }
        if(s1 == 0 && s2 == 3)    return 0;
        if(s1 == 1 && s2 == 2)    return 0;
        if(s1 == 2 && s2 != 3)    return 0;
        if(s1 == 3 && s2 == 0)    return 0;
        if(s2 == 0 && (s1 == 3 || s3 == 3))    return 0;
        if(s2 == 1 && s1 == 3 && s3 == 3)    return 0;
        if(s2 == 1 && (s1 != 3 && s3 != 3))    return 0;
        if(s2 == 2 && (s1 != 3 || s3 != 3))    return 0;
        if(s2 == 3 && (s1 == 0 || s3 == 0))    return 0;
        if(s3 == 0 && s2 == 3)    return 0;
        if(s3 == 1 && s2 == 2)    return 0;
        if(s3 == 2 && s2 != 3)    return 0;
        if(s3 == 3 && s2 == 0)    return 0;
        return 1;
    }
    
    int main() {
        freopen("mine.in", "r", stdin);
        freopen("mine.out", "w", stdout);
        scanf("%s", fi + 1);
        len = strlen(fi + 1);
        if(len == 1) {
            if(fi[1] == '0' || fi[1] == '?')    puts("1");
            else    puts("0");
            return 0;
        }
        memset(a, -1, sizeof(a));
        for(int i = 1; i <= len; i ++)
            a[i] = change(fi[i]);
        int now = 0;
        if(a[1] != 4) {
            dp[now][a[1]] = 1;
        } else dp[now][0] = dp[now][1] = dp[now][2] = dp[now][3] = 1;
        for(RG int i = 2; i <= len; i ++) {
            now ^= 1;
            memset(dp[now], 0, sizeof(dp[now]));
            for(RG int s = 0; s < (1 << 6); s ++) {
                int pre = s & (3 << 4);
                if(!check(s, i - 1))    continue;
                if(a[i] != 4) {
                    int ss = (s ^ pre) << 2 | a[i];
                    if(!check(ss, i))    continue;
                    dp[now][ss] = (dp[now ^ 1][s] + dp[now][ss]) % mod;
                } else {
                    for(RG int k = 0; k <= 3; k ++) {
                        int ss = (s ^ pre) << 2 | k;
                        if(!check(ss, i))    continue;
                        dp[now][ss] = (dp[now ^ 1][s] + dp[now][ss]) % mod;
                    }
                }
            }
        }
        LL ans = 0;
        for(int s = 0; s < (1 << 6); s ++)
            if(check(s, len))    ans = (ans + dp[now][s]) % mod;
        printf("%lld", ans);
        return 0;
    } 

    Solution

    完全把题意理解错了QAQ

    以为从每一个点开始一直就只能向上下左右四个方向走了QAQ

    结果一波暴力还得了20pts??

    正解不懂QAQ然而$zyl$dalao爆搜轻松过!

    其实也不是很暴力的搜辣,加上记忆化剪枝,大大的好!

    先预处理出可以流出去的位置们,然后对于每一个位置暴力bfs它们的所有路径QAQ,记忆化剪枝效果非常好了QAQ

    很有道理的样子呢QAQ

    我们要找的实际上就是每个点出去的每条路径上最大值的最小值,而想到最小生成树就是满足这个性质,最大边最小。

    所以按边权排序加边,两个联通块中如果一个已经有出去的节点,另一个没有,那么更新没有的那个联通块的答案就是这条新加的边权。

    吼麻烦啊QAQ

    #include<bits/stdc++.h>
    using namespace std;
    
    int h[305][305], n, m;
    int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
    
    inline void read(int &x) {
        x = 0; int t = 1; char ch = getchar();
        while(ch > '9' || ch < '0') { if(ch == '-')    t = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        x *= t;
    }
    
    bool check(int x, int y) {
        return x >= 0 && y >= 0 && x <= n + 1 && y <= m + 1;
    }
    
    int vis[305][305], vis1[305][305], ans[305][305];
    int idc, tmp;
    void dfr(int x, int y) {
        if(vis[x][y])    return ;
        vis[x][y] = 1;
        for(int k = 0; k < 4; k ++) {
            int xx = x + dx[k], yy = y + dy[k];
            if(!check(xx, yy))    ans[x][y] = 0;
            else if(h[xx][yy] <= h[x][y]) {
                dfr(xx, yy);
                if(ans[xx][yy] == 0)    ans[x][y] = 0;
            }
        }
    }
    
    bool dfs(int x, int y, int u) {
        if(vis1[x][y] == idc)    return 1;
        if(h[x][y] > u) {
            tmp = min(tmp, h[x][y] + ans[x][y]);
            return 1;
        }
        if(ans[x][y] == 0)    return 0;
        vis1[x][y] = idc;
        for(int k = 0; k < 4; k ++) {
            int xx = x + dx[k], yy = y + dy[k];
            if(!dfs(xx, yy, u))    return 0;
        }
        return 1;
    }
    
    struct Point {
        int x, y, h;
        bool operator < (const Point &t) const {
            return h > t.h;
        }
    } points[305 * 305];
    
    int main() {
        freopen("water.in", "r", stdin);
        freopen("water.out", "w", stdout);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++) {
                read(h[i][j]);
                points[(i - 1) * m + j] = (Point) {i, j, h[i][j]};
            }
        sort(points + 1, points + 1 + n * m);
        memset(ans, -1, sizeof(ans));
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)    dfr(i, j);
        for(int i = 1; i <= n * m; i ++) {
            idc ++;
            tmp = 0x3f3f3f3f;
            if(!dfs(points[i].x, points[i].y, points[i].h))
                ans[points[i].x][points[i].y] = 0;
            else    ans[points[i].x][points[i].y] = tmp - points[i].h;
        }
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++)    printf("%d ", ans[i][j]);
            printf("
    ");
        }    
        return 0;
    }
  • 相关阅读:
    Faster R-CNN
    Ubuntu软件安装
    Ubuntu16.04 caffe安装记录
    Unity Editor 工具开发 (三)——数据存储工具 -1
    #Unity Editor 工具开发 (二)
    Unity Editor 工具开发 (一)
    c# 多线程入门记录
    Unity 获取按键
    常用排序算法
    My “Hello World” For Blog
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9858438.html
Copyright © 2011-2022 走看看