zoukankan      html  css  js  c++  java
  • 【题解】APIO2013机器人

      其实这题前前后后的思考时间加起来应该有两天之久了,dp状态,转移方式等等都还是比较好想,然而左看右看觉得spfa复杂度未免太爆炸……然后选择看了一篇题解,发现在多重优化之下,其实是可以过的……

      首先建立状态,这个应该比较明显:(f[l][r][x][y]) 代表合并完区间 (l) ~(r) 之后,机器人停在 (x,y) 处所需要的最少移动次数。转移状态即为:

      (f[l][r][x][y] = f[l][k][x][y] + f[k + 1][r][x][y] left ( l <= k <= r ight ))

    (f[l][r][x][y] = f[l][r][x'][y'] + 1 )

      其中第二个转移发生的条件是 (x',y') 可以一步到达 (x,y)。第二个转移状态就是在之前的博客中所提及的那样:1.满足三角形不等式;2.不满足拓扑序;针对这样的转移,我们用 spfa 来优化 dp 的转移。注意在这张图中,边权均为1。在单源的最短路中,这样的图spfa可以优化为bfs, 在多源最短路中我们可以使用两个队列来进行优化。这两个队列分别存储新增的节点 & 被松弛所以要去松弛其余节点的节点。这样将节点分类之后,每一次取出队首元素权值更小的进行松弛操作。我们会发现第二个队列中节点的权值是单调的(在边权为1的图中,先访问到的节点权值更小),而第一个队列中的元素我们使用基数排序来排。(并不知道为什么要用基数排序,或许就是比较快吧?)

      然后这份代码是我抄的大佬的代码,非常感谢了。其中有一个小小的技巧:memset的时候默认赋给节点当前数据类型的最大值,相加会溢出。但对于这种没有正负要求的,我们可以利用 unsigned 自然溢出使得结果依然是最大值。(・ω<)☆ 感觉这题还是挺毒的,差点就被毒死了……

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 505
    #define maxk 400000
    #define uns unsigned short
    #define INF 32639
    int n, W, H, ans = INF;
    int mark[maxn][maxn][5];
    int L, R;
    uns f[12][12][maxn][maxn];
    int cnt, top, tank[maxk], S[maxk];
    char Map[maxn][maxn];
    bool vis[maxn][maxn];
    int dxy[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
    
    struct node
    {
        int x, y;
        node(int xx = 0, int yy = 0) { x = xx, y = yy; }
    }g[maxn][maxn][5], pos[11], q[maxk];
    queue <node> q1, q2;
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void gmin(uns &x, uns y) { x = x > y ? y : x; }
    
    node dfs(int x, int y, int k)
    {
        if(mark[x][y][k] == cnt) return g[x][y][k] = node (-1, -1); 
        mark[x][y][k] = cnt;
        if(g[x][y][k].x != 0 && g[x][y][k].y != 0) return g[x][y][k];
        int pre = k;
        if(Map[x][y] == 'A') k = (k + 3) % 4;
        else if(Map[x][y] == 'C') k = (k + 1) % 4;
        int xx = x + dxy[k][0], yy = y + dxy[k][1];
        if(xx < 1 || yy < 1 || xx > H || yy > W || Map[xx][yy] == 'x') return g[x][y][pre] = node(x, y);
        return g[x][y][pre] = dfs(xx, yy, k);
    }
    
    void spfa()
    {
        memset(tank, 0, sizeof(tank));
        for(int i = 1; i <= top; i ++) tank[f[L][R][q[i].x][q[i].y]] ++;
        for(int i = 1; i <= INF; i ++) tank[i] += tank[i - 1];
        for(int i = 1; i <= top; i ++) S[tank[f[L][R][q[i].x][q[i].y]] --] = i;
        for(int i = 1; i <= top; i ++) q1.push(q[S[i]]);
        top = 0;
        while(!q1.empty() || !q2.empty())
        {
            node now;
            if(q1.empty()) now = q2.front(), q2.pop();
            else if(q2.empty()) now = q1.front(), q1.pop();
            else
            {
                int x1 = q1.front().x, y1 = q1.front().y;
                int x2 = q2.front().x, y2 = q2.front().y;
                if(f[L][R][x1][y1] <= f[L][R][x2][y2]) now = q1.front(), q1.pop();
                else now = q2.front(), q2.pop();
            }
            vis[now.x][now.y] = 0;
            for(int i = 0; i < 4; i ++)
            {
                node v = g[now.x][now.y][i];
                if(v.x == -1 || v.y == -1) continue;
                if(f[L][R][v.x][v.y] > f[L][R][now.x][now.y] + 1)
                {
                    f[L][R][v.x][v.y] = f[L][R][now.x][now.y] + 1;
                    if(!vis[v.x][v.y]) vis[v.x][v.y] = 1, q2.push(v);
                }
            }
        }
    }
    
    int main()
    {
        n = read(), W = read(), H = read();
        memset(f, 127, sizeof(f));
        for(int i = 1; i <= H; i ++) 
        {
            scanf("%s", Map[i] + 1);
            for(int j = 1; j <= W; j ++) 
                if(Map[i][j] > '0' && Map[i][j] <= '9')
                    pos[Map[i][j] - '0'] = node(i, j);
        }
        for(int i = 1; i <= H; i ++)
            for(int j = 1; j <= W; j ++)
                if(Map[i][j] != 'x') 
                    for(int k = 0; k < 4; k ++)
                        ++ cnt, dfs(i, j, k);
        for(int i = 1; i <= n; i ++)
        {
            vis[pos[i].x][pos[i].y] = 1;
            q[++ top] = pos[i];
            L = R = i; f[i][i][pos[i].x][pos[i].y] = 0;
            spfa();
        }
        for(int l = 2, j; l <= n; l ++)
            for(int i = 1; (j = i + l - 1) <= n; i ++)
            {
                for(int x = 1; x <= H; x ++)
                    for(int y = 1; y <= W; y ++)
                    {
                        for(int k = i; k < j; k ++)
                            gmin(f[i][j][x][y], f[i][k][x][y] + f[k + 1][j][x][y]);
                        if(f[i][j][x][y] < INF) q[++ top] = node(x, y), vis[x][y] = 1;
                    }
                L = i, R = j; spfa();
            }
        unsigned short ans = INF;
        for(int i = 1; i <= H; i ++)
            for(int j = 1; j <= W; j ++)
                ans = min(ans, f[1][n][i][j]);
        if(ans < INF) printf("%u
    ", ans);
        else printf("-1
    ");
        return 0;
    }
  • 相关阅读:
    Java引用类型转换
    SWFUpload多文件上传使用指南
    SpringMVC中与Spring相关的@注解
    三层——c#版
    初识三层
    vb.net 总结
    设计模式总结
    设计模式系列——装饰模式
    设计模式系列——策略模式
    设计模式系列——简单工厂模式
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9097191.html
Copyright © 2011-2022 走看看