zoukankan      html  css  js  c++  java
  • bzoj2595

    状压dp+斯坦纳树

    原先就想过这个问题

    其实就是spfa优化dp,跟3875很像

    有两种转移方式,一种是枚举子集,另一种是拓展新的点,每次我们先枚举子集更新,再spfa更新dp,就是拓展新的点

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 11, inf = 0x3f3f3f3f, dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
    int n, m, p;
    int bin[N], a[N][N], t[N][N][1 << N], dp[N][N][1 << N], vis[N][N], pre[N][N][1 << N][3];
    void dfs(int x, int y, int S) 
    {
        if(!S) return; 
        vis[x][y] = 1;
        dfs(pre[x][y][S][0], pre[x][y][S][1], pre[x][y][S][2]);
        if(x == pre[x][y][S][0] && y == pre[x][y][S][1]) dfs(x, y, S ^ pre[x][y][S][2]);
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        memset(dp, 0x3f3f, sizeof(dp));
        bin[0] = 1;
        for(int i = 1; i <= 10; ++i) bin[i] = bin[i - 1] << 1;
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= m; ++j) 
            {
                scanf("%d", &a[i][j]);
                if(!a[i][j]) dp[i][j][bin[p++]] = 0;
            }
        for(int S = 1; S < bin[p]; ++S) 
        {
            queue<int> q; 
            for(int i = 1; i <= n; ++i)
                for(int j = 1; j <= m; ++j) 
                    for(int S0 = S; S0; S0 = (S0 - 1) & S) 
                    {
                        int tmp = dp[i][j][S ^ S0] + dp[i][j][S0] - a[i][j];
                        if(tmp < dp[i][j][S]) 
                        {
                            dp[i][j][S] = tmp;
                            pre[i][j][S][0] = i;
                            pre[i][j][S][1] = j;
                            pre[i][j][S][2] = S0;
                        }
                        if(dp[i][j][S] < inf) 
                        {
                            t[i][j][S] = 1;
                            q.push(i);
                            q.push(j);
                            q.push(S);
                        }
                    }
            while(!q.empty()) 
            {
                int x = q.front(); q.pop();
                int y = q.front(); q.pop();
                int S = q.front(); q.pop();
                t[x][y][S] = 0;
                for(int i = 0; i < 4; ++i) 
                {
                    int xx = x + dx[i], yy = y + dy[i];
                    if(xx > 0 && xx <= n && yy > 0 && yy <= m && dp[xx][yy][S] > dp[x][y][S] + a[xx][yy])
                    {
                        dp[xx][yy][S] = dp[x][y][S] + a[xx][yy];
                        pre[xx][yy][S][0] = x;
                        pre[xx][yy][S][1] = y;
                        pre[xx][yy][S][2] = S;
                        if(!t[xx][yy][S]) 
                        {
                            t[xx][yy][S] = 1;
                            q.push(xx);
                            q.push(yy);
                            q.push(S);
                        } 
                    }
                }   
            }   
        }   
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= m; ++j) if(!a[i][j]) 
            {
                printf("%d
    ", dp[i][j][bin[p] - 1]);
                dfs(i, j, bin[p] - 1);
                for(int x = 1; x <= n; ++x)
                {
                    for(int y = 1; y <= m; ++y) 
                    {
                        if(a[x][y]) printf("%c", vis[x][y] ? 'o' : '_');
                        else printf("x");
                    }
                    puts("");
                }
                return 0;
            }   
        return 0;
    }
    
    View Code
  • 相关阅读:
    hbuilder中如何使用egit上传项目
    网络攻防第二周学习笔记
    sqlserver两表关联的更新
    ISAPI_rewrite中文手册
    Unity中C#单例模式使用总结
    Window Live Writer Test
    Spring Cloud 服务注册与发现(Eureka 找到了!找到了! 嘻嘻)
    Spring Cloud 服务消费与负载均衡(feign)
    Spring Cloud 服务消费与负载均衡(Rest + Ribbon )
    列表的响应式排版
  • 原文地址:https://www.cnblogs.com/19992147orz/p/8034587.html
Copyright © 2011-2022 走看看