• bzoj2143 飞飞侠


    2143: 飞飞侠

    Time Limit: 50 Sec  Memory Limit: 259 MB
    Submit: 1158  Solved: 399
    [Submit][Status][Discuss]

    Description

    飞飞国是一个传说中的国度,国家的居民叫做飞飞侠。飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹射能力。并规定有相邻边的格子间距离是1。那么,任何飞飞侠都只需要在(i,j)支付Aij的费用就可以任意选择弹到距离不超过Bij的位置了。如下图  (从红色街区交费以后可以跳到周围的任意蓝色街区。) 现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的费用总和最低。

    Input

    输入的第一行包含两个整数N和M,分别表示行数和列数。接下来是2个N×M的自然数矩阵,为Bij和Aij 最后一行六个数,分别代表X,Y,Z所在地的行号和列号。

    Output

    第一行输出一个字符X、Y或者Z。表示最优集合地点。第二行输出一个整数,表示最小费用。如果无法集合,只输出一行NO

    Sample Input

    4 4
    0 0 0 0
    1 2 2 0
    0 2 2 1
    0 0 0 0
    5 5 5 5
    5 5 5 5
    5 5 5 5
    5 5 5 5
    2 1 3 4 2 2

    Sample Output

    Z
    15
    【范围】
    100% 1 < = N, M < = 150; 0 < = Aij < = 10^9; 0 < = Bij < = 1000
    分析:非常好的一道题!
         很容易能看出这道题其实考的就是最短路,但是边数太多了,直接上会T掉.这是最短路中的一类问题,如何把连的边变少?
       我做过的这类题中有设置一个入点和出点的,然后把边通过这两个点相连,也有对输入做某些处理,得出性质,知道哪些边是无用的,删去.这道题要用到将边等价的思想.
       可以把弹射距离看作能量,如果能量为0则必须原地不动充能,花费为a[i][j],如果有能量,则向相邻方向移动一格不需要花费,能量-1.这样整个图就变成了每个点向四周的点连边.
       维护的图其实是一个分层图,设f[i][j][k]表示走到点(i,j)处,还有k点能量的最小花费.vis数组也要记录三维的vis[i][j][k].如果直接跑spfa会超时,需要用dijkstra.如果直接跑dijkstra还是会超时.怎么优化呢?如果已经走到了X,Y,Z三个点,并且X,Y,Z三个点的答案不会再被更新了,那么就可以返回了.怎么维护?
       在向4周走的操作上再加一个操作:原地不动,并不充能.这样所有的答案都会汇集到vis[i][j][0]上,只要判断X,Y,Z的vis[0]是不是都被访问过即可.但这能保证XYZ不会继续被更新吗?根据dijkstra算法的性质,我们用小根堆维护,每次移动花费最小的点,既然已经更新到vis[0]了,那么以后所有的花费肯定都比当前大,故不可能更新了.
       最后统计答案的时候注意不要弄混了.每次选择dijkstra选定的是起点,统计的是终点.
       这道题加深了我对最短路如何少连边和dijkstra算法的理解,挺不错的啊.
       附上另外几道题的链接:bzoj41522017计蒜之道复赛百度地图导航.
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int dx[] = {0,0,1,-1,0},dy[] = {1,-1,0,0,0};
    const ll inf = 10000000000000000;
    const int maxn = 151;
    int n,m;
    ll cost[maxn][maxn],b[maxn][maxn],X[4],Y[4],f[maxn][maxn][maxn * 2];
    bool vis[maxn][maxn][maxn * 2];
    ll a1,a2,b1,b2,c1,c2,ans;
    
    struct node
    {
        ll x,y,nowcost,lastenergy;
        bool operator < (const node &a) const
        {
            return nowcost > a.nowcost;
        }
    };
    
    void dijkstra(int pos)
    {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                for (int k = 0; k <= n + m; k++)
                {
                    vis[i][j][k] = 0;
                    f[i][j][k] = inf;
                }
        priority_queue<node> q;
        node temp;
        temp.x = X[pos];
        temp.y = Y[pos];
        temp.nowcost = cost[X[pos]][Y[pos]];
        temp.lastenergy = b[X[pos]][Y[pos]];
        q.push(temp);
        vis[X[pos]][Y[pos]][0] = 1;
        f[X[pos]][Y[pos]][temp.lastenergy] = cost[X[pos]][Y[pos]];
        while (!q.empty())
        {
            if (vis[X[1]][Y[1]][0] && vis[X[2]][Y[2]][0] && vis[X[3]][Y[3]][0])
                return;
            node u = q.top();
            q.pop();
            ll x = u.x,y = u.y,k = u.lastenergy;
            if (vis[x][y][k])
                continue;
            vis[x][y][k] = 1;
            if (u.lastenergy)
            {
                for (int i = 0; i <= 4; i++)
                {
                    ll nx = x + dx[i],ny = y + dy[i];
                    if (nx >= 1 && nx <= n && ny >= 1 && ny <= m)
                    {
                        if (f[nx][ny][k - 1] > f[x][y][k])
                        {
                            f[nx][ny][k - 1] = f[x][y][k];
                            node temp;
                            temp.x = nx;
                            temp.y = ny;
                            temp.lastenergy = k - 1;
                            temp.nowcost = f[nx][ny][k - 1];
                            q.push(temp);
                        }
                    }
                }
            }
            else
            {
                if (f[x][y][0] + cost[x][y] < f[x][y][b[x][y]])
                {
                    f[x][y][b[x][y]] = f[x][y][0] + cost[x][y];
                    node temp;
                    temp.x = x;
                    temp.y = y;
                    temp.lastenergy = b[x][y];
                    temp.nowcost = f[x][y][b[x][y]];
                    q.push(temp);
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                scanf("%lld",&b[i][j]);
                b[i][j] = min(b[i][j],1LL * (max(i - 1,n - i) + max(j - 1,m - j)));
            }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%lld",&cost[i][j]);
        for (int i = 1; i <= 3; i++)
            scanf("%lld%lld",&X[i],&Y[i]);
        dijkstra(1);
        a1 = f[X[2]][Y[2]][0],a2 = f[X[3]][Y[3]][0];
        dijkstra(2);
        b1 = f[X[1]][Y[1]][0],b2 = f[X[3]][Y[3]][0];
        dijkstra(3);
        c1 = f[X[1]][Y[1]][0],c2 = f[X[2]][Y[2]][0];
        ans = inf;
        char anss;
        if (b1 + c1 < ans)
        {
            ans = b1 + c1;
            anss = 'X';
        }
        if (a1 + c2 < ans)
        {
            ans = a1 + c2;
            anss = 'Y';
        }
        if (a2 + b2 < ans)
        {
            ans = a2 + b2;
            anss = 'Z';
        }
        if (ans >= inf)
            printf("NO");
        else
            cout << anss << endl << ans << endl;
    
        return 0;
    }
  • 相关阅读:
    windbg 内核模式调试用户进程
    深发展银行编码器(解剖)
    SIM300常用命令
    tdi驱动 for vista or later
    vm命令行控制 (vmrun)
    WMI事件监控
    Visual C++ 中 #pragma 指示符的使用
    IOCP开发的几个概念
    移动web.config文件时造成的错误,
    提高网站速度|页面优化
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8446435.html
Copyright © 2020-2023  润新知