• bzoj3205 [Apio2013]机器人


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

    http://uoj.ac/problem/107

    【题解】

    我们发现这就是一棵斯坦纳树啊。。

    令f[l,r,a,b]表示合并了(l,r),当前在(a,b)的最小推的次数。

    预处理出来每个点朝每个方向推一下到哪里。(dfs,注意处理循环情况)

    然后我们就可以套斯坦纳树板子了。

    但是发现过不了。。因为spfa好像复杂度不对?

    由于spfa边权都是1,所以我们用bfs来扩展。

    我们把原有的节点按照f值排序,然后维护一个栈来存储原有的节点,用一个队列存储扩展的节点。

    容易发现这两个里面都是单调的。每次比较头即可。

    然后复杂度对了。。注意要基数排序(?)

    然后基数排序数组要开大啊不然会RE...

    大概100w?

    bzoj怎么都能过系列。

    # include <queue>
    # include <cctype>
    # 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 = 503, N = 10, F = 6e5 + 3, FF = 1e6 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, W, H; 
    char mp[M][M];
    int f[N][N][M][M];
    
    struct pa {
        int x, y;
        pa() {}
        pa(int x, int y) : x(x), y(y) {}
        friend bool operator == (pa a, pa b) {
            return a.x==b.x && a.y==b.y;
        }
        friend bool operator != (pa a, pa b) {
            return !(a==b);
        }
    };
    
    int dfs_clock;
    pa dp[M][M][4];
    int v[M][M][4];
    // 0: up, 1: right, 2: down, 3: left
    const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    
    inline pa dfs(int x, int y, int face) {
        if(v[x][y][face] == dfs_clock) return pa(-1, -1);
        v[x][y][face] = dfs_clock;
        if(dp[x][y][face] != pa(0, 0)) return dp[x][y][face];
        int nface = face, nx = x, ny = y;
        if(mp[x][y] == 'A') nface = (nface+3)%4;
        if(mp[x][y] == 'C') nface = (nface+1)%4;
        nx += dx[nface], ny += dy[nface];
        if(nx<=0 || ny<=0 || nx>H || ny>W) return dp[x][y][face] = pa(x, y);
        if(mp[nx][ny] == 'x') return dp[x][y][face] = pa(x, y);
        return dp[x][y][face] = dfs(nx, ny, nface);
    }
    
    
    pa q[F], st[F];
    bool vis[M][M];
    int su[FF], va[F], vn=0, stn;
    
    inline void spfa(int sti, int stj) {
        int head = 1, tail = 0;
        memset(su, 0, sizeof su); vn = 0;
        int mx = -1e9, mi = 1e9;
        for (int i=1; i<=H; ++i)
            for (int j=1; j<=W; ++j)
                if(f[sti][stj][i][j] != 1e9) {
                    q[++tail] = pa(i, j);
                    va[++vn] = f[sti][stj][i][j];
                    su[va[vn]] ++;
                    if(va[vn] > mx) mx = va[vn];
                    if(va[vn] < mi) mi = va[vn];
                    vis[i][j] = 1;
                }
        for (int i=mi; i<=mx; ++i) su[i] += su[i-1];    
        for (int i=1; i<=vn; ++i) st[su[va[i]]--] = q[i]; stn = vn;
        reverse(st+1, st+stn+1);
        head = 1, tail = 0;
        while(head <= tail || stn) {
            pa t;
            if(head > tail) {
                t = st[stn];
                --stn;    
            } else if(!stn) {
                t = q[head];
                ++head;
            } else {
                int ta = f[sti][stj][q[head].x][q[head].y], tb = f[sti][stj][st[stn].x][st[stn].y];
                if(ta < tb) t = q[head], ++head;
                else t = st[stn], --stn;
            }
            vis[t.x][t.y] = 0;
            for (int i=0; i<4; ++i) {
                int nx = dp[t.x][t.y][i].x, ny = dp[t.x][t.y][i].y;
                if(nx == -1) continue;
                if(f[sti][stj][t.x][t.y]+1 < f[sti][stj][nx][ny]) {
                    f[sti][stj][nx][ny] = f[sti][stj][t.x][t.y]+1;
                    if(!vis[nx][ny]) {
                        vis[nx][ny] = 1;
                        q[++tail] = pa(nx, ny);
                    }
                }
            }
        }
    }
    
    inline void debug() {
        for (int sti=1; sti<=n; ++sti)
            for (int stj=sti; stj<=n; ++stj)
                for (int i=1; i<=H; ++i)
                    for (int j=1; j<=W; ++j) printf("(%d, %d) (H,W: %d, %d) %d
    ", sti, stj, i, j, f[sti][stj][i][j]);
    //    system("pause");
    }
    
    int main() {
        scanf("%d%d%d", &n, &W, &H);
        for (int i=1; i<=H; ++i) scanf("%s", mp[i]+1);
        for (int i=1; i<=H; ++i)
            for (int j=1; j<=W; ++j)
                for (int face=0; face<4; ++face)
                    if(mp[i][j] == 'x') dp[i][j][face] = pa(-1, -1);
                    else dp[i][j][face] = pa(0, 0);
        for (int i=1; i<=H; ++i)
            for (int j=1; j<=W; ++j) 
                for (int face=0; face<4; ++face) {
                    dfs_clock++;
                    dp[i][j][face] = dfs(i, j, face);
                }
    //    for (int i=1; i<=H; ++i)
    //        for (int j=1; j<=W; ++j)
    //            for (int face=0; face<4; ++face) 
    //                printf("i=%d, j=%d, face=%d,  dp[i][j][face] = (%d, %d)
    ", i, j, face, dp[i][j][face].x, dp[i][j][face].y);
        
        for (int sti=1; sti<=n; ++sti)
            for (int stj=sti; stj<=n; ++stj)
                for (int i=1; i<=H; ++i)
                    for (int j=1; j<=W; ++j)
                        f[sti][stj][i][j] = 1e9;
    
        for (int i=1; i<=H; ++i)
            for (int j=1; j<=W; ++j)
                if(isdigit(mp[i][j])) {
                    int t = mp[i][j] - '0';
                    f[t][t][i][j] = 0;
                }
        
        for (int len=1; len<=n; ++len) 
            for (int sti=1; sti<=n-len+1; ++sti) {
                int stj = sti + len - 1;
                // (sti, stj)  status
                for (int i=1; i<=H; ++i)
                    for (int j=1; j<=W; ++j) 
                        for (int st = sti; st < stj; ++st)
                            f[sti][stj][i][j] = min(f[sti][stj][i][j], f[sti][st][i][j] + f[st+1][stj][i][j]);
                spfa(sti, stj);
            }
    //    debug();    
        
        int ans = 1e9;
        for (int i=1; i<=H; ++i)
            for (int j=1; j<=W; ++j)
                ans = min(ans, f[1][n][i][j]);
        printf("%d
    ", ans == 1e9 ? -1 : ans);
        
        return 0;
    }
    View Code
  • 相关阅读:
    在Vue-cli3.x中引入element-ui的新方式
    通过JS屏蔽鼠标右键
    java异常有效实践
    设计之禅——迭代器模式
    设计之禅——状态模式
    设计之禅——外观模式
    设计之禅——适配器模式
    设计之禅——我只要结果(命令模式)
    设计之禅——装饰者模式详解(与代理模式的区别以及与其他模式的组合)
    设计之禅——生成器模式
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3205.html
Copyright © 2020-2023  润新知