• bzoj2595 [Wc2008]游览计划


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595

    【题解】

    斯坦纳树模板题。学了一发斯坦纳树。

    对于一般的斯坦纳树,是 给出一些点和一些关键点和边,要求选择权值和最小的连通块使得关键点连通。

    那么一般我们用f(x,status)表示在x,状态为status的最小权值和。

    本题我们采用f(i,j,status)表示在(i,j),状态为status的最小权值和。

    一开始权值就是题目给的,如果是景点那么在对应的标号的status赋值即可。

    首先可以分成两个部分来转移:f(i,j,status) = f(i, j, subset) + f(i, j, status - subset) - mp[i][j]

    (也就是枚举子集,因为(i,j)被多算了一次,所以要减掉)

    另外一面,f(i, j, status) = min(f(i', j', s') + mp[i][j])

    (从周围四个格子转移过来,增加一个格子,如果是景点需要特别处理下s')

    这个式子长得非常像最短路,所以我们可以用spfa来解决。

    然后就处理完了。接着说输出答案。

    我们记录从哪里转移得到即可。递归下去处理答案并输出。

    好麻烦啊qwq第一次题解写这么长呀。

    不过斯坦纳树应用好像不大多,了解就行。

    【update】原来的板子。。这题能过但是其他题目好像跑的贼慢,更新了新板子

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 10 + 10, STATUS = 1027, N = 500010;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, k = 0;
    int mp[M][M], st[M][M]; 
    int f[M][M][STATUS]; 
    const int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1}; 
    
    struct pa {
        int i, j, s;
        pa() {}
        pa(int i, int j, int s) : i(i), j(j), s(s) {}
        inline int set() {
            return i+11*j+11*11*s; 
        }
        friend bool operator == (pa a, pa b) {
            return a.i == b.i && a.j == b.j && a.s == b.s;
        }
    };
    
    pa from[M][M][STATUS]; 
    queue< pair<int,int> > q;
    bool vis[M][M];
    bool ans[M][M];
    
    inline void spfa(int status) {
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j)
                vis[i][j] = 1, q.push(make_pair(i, j));
        while(!q.empty()) {
            pair<int,int> top=q.front(); q.pop(); vis[top.first][top.second] = 0; 
            for (int i=0; i<4; ++i) {
                int xx=top.first+dx[i], yy=top.second+dy[i];
                if(xx<1||xx>n||yy<1||yy>m) continue;
                if(f[xx][yy][status] > f[top.first][top.second][status] + mp[xx][yy]) {
                    f[xx][yy][status] = f[top.first][top.second][status] + mp[xx][yy];
                    from[xx][yy][status] = pa(top.first, top.second, status);
                    if(!vis[xx][yy]) {
                        vis[xx][yy] = 1;
                        q.push(make_pair(xx, yy));
                    }
                }
            }
        }
    }
    inline void getans(int x, int y, int s) {
        ans[x][y] = 1;
        pa t = from[x][y][s]; 
        if(t == pa(-1, -1, -1)) return ;
        getans(t.i, t.j, t.s);
        if(t.i==x && t.j==y) getans(t.i, t.j, s-t.s);
    }
    
    int main() {
        for (int i=1; i<=10; ++i)
            for (int j=1; j<=10; ++j)
                for (int k=0; k<=1025; ++k) f[i][j][k] = 1e9, from[i][j][k] = pa(-1, -1, -1); 
        scanf("%d%d", &n, &m);
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j) {
                f[i][j][0] = mp[i][j];
                scanf("%d", &mp[i][j]); 
                if(mp[i][j] == 0)
                    f[i][j][1<<k] = 0, st[i][j] = (1<<k), ++k; 
            }
        int status_size = (1<<k)-1;
        for (int status=1; status<=status_size; ++status) {
            for (int i=1; i<=n; ++i)
                for (int j=1; j<=m; ++j) { 
                    for (int ss = status-1&status; ss; ss=ss-1&status) {
                        if(f[i][j][status] > f[i][j][ss] + f[i][j][status^ss] - mp[i][j]) {
                            f[i][j][status] = f[i][j][ss] + f[i][j][status^ss] - mp[i][j];
                            from[i][j][status] = pa(i, j, ss);
                        }
                    }
                }
            spfa(status);
        }
        
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j) {
                if(!mp[i][j]) {
                    printf("%d
    ", f[i][j][status_size]);
                    getans(i, j, status_size);
                    for (int x=1; x<=n; ++x, puts(""))
                        for (int y=1; y<=m; ++y)
                            if(ans[x][y]) {
                                if(mp[x][y]) printf("o");
                                else printf("x");
                            } else printf("_"); 
                    i = n+1, j = m+1;
                }
            }
        return 0;
    }
    View Code
  • 相关阅读:
    java实习生面试
    使用vue可视化界面创建vue项目
    Git操作分支
    ECharts获取Json文件数据
    Java中字符串反转
    es6新增的API
    es5新增的数组的方法
    操作字符串的相关方法
    排序方法总结
    js内置对象-Array
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj2595.html
Copyright © 2020-2023  润新知