zoukankan      html  css  js  c++  java
  • 【图论-最短路】【P3393】逃离僵尸岛

    传送门

    Description

    小a住的国家被僵尸侵略了!小a打算逃离到该国唯一的国际空港逃出这个国家。

    该国有N个城市,城市之间有道路相连。一共有M条双向道路。保证没有自环和重边。

    K个城市已经被僵尸控制了,如果贸然闯入就会被感染TAT...所以不能进入。由其中任意城市经过不超过S条道路就可以到达的别的城市,就是危险城市。换句话说只要某个没有被占城市到某个被占城市不超过s距离,就是危险。

    小a住在1号城市,国际空港在N号城市,这两座城市没有被侵略。小a走每一段道路(从一个城市直接到达另外一个城市)得花一整个白天,所以晚上要住旅店。安全的的城市旅馆比较便宜要P元,而被危险的城市,旅馆要进行安保措施,所以会变贵,为Q元。所有危险的城市的住宿价格一样,安全的城市也是。在1号城市和N城市,不需要住店。

    小a比较抠门,所以他希望知道从1号城市到N号城市所需要的最小花费。

    输入数据保证存在路径,可以成功逃离。输入数据保证他可以逃离成功。

    Input

    第一行4个整数(N,M,K,S)

    第二行2个整数(P,Q)

    接下来K行,ci,表示僵尸侵占的城市

    接下来M行,ai,bi,表示一条无向边

    Output

    一个整数表示最低花费

    Sample Input

    13 21 1 1
    1000 6000
    7
    1 2
    3 7
    2 4
    5 8
    8 9
    2 5
    3 4
    4 7
    9 10
    10 11
    5 9
    7 12
    3 6
    4 5
    1 3
    11 12
    6 7
    8 11
    6 13
    7 8
    12 13

    Sample Output

    11000

    Hint

    对于100%数据,2 ≦ N ≦ 100000, 1 ≦ M ≦ 200000, 0 ≦ K ≦ N - 2, 0 ≦ S ≦ 100000

    1 ≦ P < Q ≦ 100000

    Solution

      思路十分清晰:先求出所有是危险区域的点,然后跑一遍spfa。

      以下为了叙述方便,记被占领的点为黑色的点,危险的点为灰色的点,安全的点为白色的点。

      但是怎么求灰色的点呢?暴力的方法当然是直接枚举所有黑色的点,各跑一遍spfa。然后存下来,但是一共最多有n(同阶)个点,spfa最多要n(同阶)层……然后你就炸了

      考虑我们在这一遍spfa的时候并不需要清楚的知道它离我们规定的起点的距离。只需要知道它离距离他最近的点的距离即可。所以我们可以一次性把所有的黑色点压到队列里面一起spfa。这样我们的frog数组确切的含义就是距离他最近的黑色点离他的距离。

      然后我们使用数组记录那些点是灰色的,然后跑一边真正的spfa。

      几个坑点:1、long long

           2、黑色点不能走

           3、最后一个点和第一个点不需要算点权。

           4、由于我们每条路走过去都可能由两个花费,所以不能在spfa第一次搜到目标点的时候直接输出exit(0).(这点好像很基础但我太久没写忘了)

    Code

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #define int long long
    #define maxn 100010
    #define maxm 400010
    
    inline void qr(int &x) {
        char ch=getchar();int f=1;
        while(ch>'9'||ch<'0')    {
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')    x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x*=f;
        return;
    }
    
    inline int max(const int &a,const int &b) {if(a>b) return a;else return b;}
    inline int min(const int &a,const int &b) {if(a<b) return a;else return b;}
    inline int abs(const int &x) {if(x>0) return x;else return -x;}
    
    inline void swap(int &a,int &b) {
        int c=a;a=b;b=c;return;
    }
    
    int n,m,k,s,p,q;
    
    const long long INF = (1ll<<62);
    
    struct Edge {
        int to,nxt;
    };
    Edge edge[maxm];int hd[maxn],ecnt;
    inline void cont(const int &from,const int&to) {
        edge[++ecnt].to=to;
        edge[ecnt].nxt=hd[from];
        hd[from]=ecnt;
    }
    
    int a,b,c[maxn],frog[maxn],ans=1926081700000;
    bool dangerous[maxn],cant[maxn];
    std::queue<int>Q;
    
    void jiadespfa() {                            //拼音大法好
        for(int i=1;i<=n;++i)    frog[i]=INF;
        for(int i=1;i<=k;++i)    {frog[c[i]]=0;Q.push(c[i]);cant[c[i]]=true;}
        while(!Q.empty()) {
            int h=Q.front();Q.pop();
            for(int i=hd[h];i;i=edge[i].nxt) {
                int &to=edge[i].to;
                if(frog[to]>frog[h]+1) {
                    frog[to]=frog[h]+1;if(frog[to]<=s) {
                        dangerous[to]=true;Q.push(to);
                    }
                }
            }
        }
    }
    
    void zhendespfa() {                            //拼音大法好
        for(int i=1;i<=n;++i)    frog[i]=INF;
        frog[1]=0;Q.push(1);
        while(!Q.empty()) {
            int h=Q.front();Q.pop();
            for(int i=hd[h];i;i=edge[i].nxt) {
                int &to=edge[i].to;int v=(dangerous[to]?q:p);
                if(cant[to])    continue;
                if(to==n) {
                    ans=min(ans,frog[h]);
                    continue;
                }
                if(frog[to]>frog[h]+v) {
                    frog[to]=frog[h]+v;Q.push(to);
                }
            }
        }
    }
    
    main() {
        qr(n);qr(m);qr(k);qr(s);qr(p);qr(q);
        for(int i=1;i<=k;++i)    qr(c[i]);
        for(int i=1;i<=m;++i) {
            a=b=0;qr(a);qr(b);cont(a,b);cont(b,a);
        }
        jiadespfa();
        zhendespfa();
        printf("%lld
    ",ans);
        return 0;
    }

    Summary

      1、在不需要确切知道当前点和目标点的距离,而是需要知道每个点和给定的一些点的最近距离时,可以把给定的点全部压到队列里面,一起spfa。

       2、spfa不能搜到就输出(这不是废话吗……要不然直接bfs不就成了)

  • 相关阅读:
    POJ 1741 Tree(树分治)
    HDU 2196 Computer(树形dp)
    2015沈阳区域赛Meeting(最短路 + 建图)
    make the fence great again(dp 二维)
    2017沈阳区域赛Infinite Fraction Path(BFS + 剪枝)
    bitset详解
    2016青岛区域赛.Coding Contest(费用流 + 概率计算转换为加法计算)
    2019上海网络赛B题(差分 + 离散化 or 差分 + 思维)
    poj-1664.放苹果.(递推)
    hdu-4738.Caocao's Bridges(图中权值最小的桥)
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9245401.html
Copyright © 2011-2022 走看看