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\n", 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

 

posted @ 2017-12-13 19:44  19992147  阅读(162)  评论(0编辑  收藏  举报