题解——逃离僵尸岛(BFS+最短路+虚拟节点)

题解——逃离僵尸岛(BFS+最短路+虚拟节点)

一道很巧妙的最短路问题,细节也要注意


题面

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
一个整数表示最低花费

in.1
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

out.1
11000

数据范围与约定
对于20%数据,N<=50
对于100%数据,2 ≦ N ≦ 100000, 1 ≦ M ≦ 200000, 0 ≦ K ≦ N - 2, 0 ≦ S ≦ 100000
1 ≦ P < Q ≦ 100000

思路

主要分为两部分:

1.处理出哪些点是危险节点,哪些点是安全节点。
2.点权下放为边权

处理:
1.显然不可能对每一个僵尸围城的点做一次BFS,显然超时,原因就是有重复点被多次遍历,如果我们仅用vis数组判重,又会截断点之间的深度deep关系(可能有更加浅的点来更新这个点)。
所以,我们建立一个虚拟源点,向所有僵尸围城的点连单向边。(由于ssw02只建一个图,所以单向边,绝对不能返回 ),这样可以较好地保持点之间的深度deep关系。

2.这道题很特殊,一条单向边的边权之和这条边的目的地有关,我们只要处理问题一,把每一条边抽出来加边权即可。

细节:
1.初始用虚拟源点时只能连单向边。
2.如果只用一个图,注意初始边权为0,后面加边权。
3.加边权时注意优先级!!
4.加边权时,碰到僵尸围城的点,把两条边都赋值为inf (严格意义下加指向其的单边也行)
5.边的数量会因为虚拟的边而增多 100000 条 单向边(这可以不乘2)

AC code: 我写的相当简洁

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 100005 , MAXM = 200005 + 100000 ;//多加的边数
inline int read(){
    int s=0 ; char g=getchar() ;while(g>'9'||g<'0')g=getchar() ;
    while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar();return s ;
}
int  N , M , K , S , Q1 , Q2 , head[ MAXN ] , danger[ MAXN ] , to[ MAXM*2 ] , nex[ MAXM*2 ]  , tot = 1 ;
ll dis[ MAXN ] , w[ MAXM*2 ] ;
bool vis[ MAXN ]  ;
priority_queue< pair<ll,int> >q ;
queue< pair<int,int> >ql ;
void  add( int  x , int  y , int  z ){
    to[ ++tot ] = y , nex[ tot ] = head[ x ] ,w[ tot ] = z , head[ x ] = tot ;
}
void  bfs(){
    ql.push( make_pair(0,0) ) ;
    vis[ 0 ] = true ;
    while( !ql.empty() ){
        int  u = ql.front().first , dep = ql.front().second ; ql.pop() ;
        for( int i = head[ u ] ; i ; i = nex[ i ] ){
            if( vis[ to[ i ] ] || dep > S )continue ;
            ql.push( make_pair( to[ i ] , dep+1 ) ) ;
            vis[ to[i] ] = true , danger[ to[ i ] ] = max( danger[ to[i] ] , 1 ) ;
        }
    }
}
void  dijkstra(){
    for( int i = 1 ; i <= N ; ++i )dis[ i ] = 20000000005 ;//题意所得最大 20000000000
    dis[ 1 ] = 0 ;
    q.push( make_pair( 0LL,1 ) ) ;
    while( !q.empty() ){
        int  u = q.top().second ; q.pop() ;
        if( vis[ u ] )continue ;
        vis[ u ] = true ;
        for( register int i = head[ u ] ; i ; i = nex[ i ] ){
            if( dis[ to[ i ] ] > dis[ u ] + w[ i ] ){
                dis[ to[ i ] ] = dis[ u ] + w[ i ] ;
                q.push( make_pair( -dis[ to[ i ] ] , to[ i ] ) ) ;
            }
        }
    }
}
int main(){
    N = read() , M = read() , K = read() , S = read() , Q1 = read() , Q2 = read() ;
    int m1 , m2 ;
    for( int i = 1 ; i <= K ; ++i ){
        m1 = read() , danger[ m1 ] = 2 , add( 0 , m1 , 0 ) ;//单向
    }
    if( K%2 )tot++ ; K = tot ;
    for( int i = 1 ; i <= M ; ++i ){
        m1 = read() , m2 = read() ;
        add( m1 , m2 , 0 ) ; add( m2 , m1 , 0 ) ;
    }
    bfs() ;
    memset( vis , false , sizeof(vis) ) ;
    for( int i = K ; i <= tot ; ++i ){//点权下放,分配边权
        if( w[ i ] )continue ;
        if( danger[ to[i] ] == 2 ){w[ i ] = w[ i^1 ] = 20000000005 ;}
        else if( danger[ to[i] ] == 1 )w[ i ] = Q2 ;
            else w[ i ] = Q1 ;
        w[ i ] = ( to[ i ]  == 1 || to[ i ] == N )? 0 : w[ i ] ;
    }
    dijkstra() ;
    cout<<dis[ N ] ;
    return 0 ;
}

ssw02 的得分 42 -> 28 -> 57 -> 100 真是什么情况ssw02都撞上了

如有不足,请大佬指出

原文地址:https://www.cnblogs.com/ssw02/p/11402714.html

时间: 2024-10-30 16:05:33

题解——逃离僵尸岛(BFS+最短路+虚拟节点)的相关文章

Luogu P3393 逃离僵尸岛【最短路】By cellur925

题目传送门 题目大意:(其实概括出来也就基本做完了hh)在一张有$n$个点,$m$条边的无向图上,有$k$个点是不能经过的,而与之距离不超过$s$的点,到他们会花费$Q$元,到其他点会花费$p$元,求1到$n$花费的最小价钱. 概括完题意也就非常明了了.我们需要把图上的点分为三类,这部分可以由一个$bfs$求得. void bfs() { while(!q1.empty()) { int u=q1.front().second; int val=q1.front().first;q1.pop()

题解 P3393 【逃离僵尸岛】

题解 P3393 [逃离僵尸岛] 题目链接 没错这题就是单元最短路径的裸题. 同时也可以练习一下多源BFS 在处理被占领点周围的"危险点"时我们可以使用bfs,对于k个被占领点一个一个BFS显然太慢没有B格了,所以我们可以多源BFS,也就是第一次就把所有的被占领点压到队列里. 染完色以后处理每个点的权值,危险点的权值设为q,安全点的权值设为p,被占领的点权值设为一个比较大的数. 然后从点1跑最短路径就行了. 总之这是一道有点细节的模板题,要开long long不然玄学错误 代码: /*

AC日记——逃离僵尸岛 洛谷 P3393

逃离僵尸岛 思路: spfa: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 200005 #define maxque 1800056 #define INF 1e12 #define ll long long ll n,m,E[maxque],V[maxque],cnt,

洛谷⑨月月赛Round2 P3393逃离僵尸岛[最短路]

题目描述 小a住的国家被僵尸侵略了!小a打算逃离到该国唯一的国际空港逃出这个国家. 该国有N个城市,城市之间有道路相连.一共有M条双向道路.保证没有自环和重边. K个城市已经被僵尸控制了,如果贸然闯入就会被感染TAT...所以不能进入.由其中任意城市经过不超过S条道路就可以到达的别的城市,就是危险城市.换句话说只要某个没有被占城市到某个被占城市不超过s距离,就是危险. 小a住在1号城市,国际空港在N号城市,这两座城市没有被侵略.小a走每一段道路(从一个城市直接到达另外一个城市)得花一整个白天,所

洛谷P3393 逃离僵尸岛

题目描述 小a住的国家被僵尸侵略了!小a打算逃离到该国唯一的国际空港逃出这个国家. 该国有N个城市,城市之间有道路相连.一共有M条双向道路.保证没有自环和重边. K个城市已经被僵尸控制了,如果贸然闯入就会被感染TAT...所以不能进入.由其中任意城市经过不超过S条道路就可以到达的别的城市,就是危险城市.换句话说只要某个没有被占城市到某个被占城市不超过s距离,就是危险. 小a住在1号城市,国际空港在N号城市,这两座城市没有被侵略.小a走每一段道路(从一个城市直接到达另外一个城市)得花一整个白天,所

P3393 逃离僵尸岛

题目描述 小a住的国家被僵尸侵略了!小a打算逃离到该国唯一的国际空港逃出这个国家. 该国有N个城市,城市之间有道路相连.一共有M条双向道路.保证没有自环和重边. K个城市已经被僵尸控制了,如果贸然闯入就会被感染TAT...所以不能进入.由其中任意城市经过不超过S条道路就可以到达的别的城市,就是危险城市.换句话说只要某个没有被占城市到某个被占城市不超过s距离,就是危险. 小a住在1号城市,国际空港在N号城市,这两座城市没有被侵略.小a走每一段道路(从一个城市直接到达另外一个城市)得花一整个白天,所

逃离僵尸岛

[题目描述] 现有N个城市,城市之间有道路相连,一共有M条双向道路,保证没有自环和重边. 现有K个城市已经被僵尸控制,所以不能进入.若某个正常城市到某个僵尸城市的距离不超过S,则称此城市为危险城市. 小A住在1号城市,他想去N号城市避难,这两座城市没有被侵略.白天小A会走一段道路,晚上要住在所处城市.在正常城市需花费P元,而在危险城市,由于安保措施,所以会变贵,为Q元.所有危险城市的住宿花费相同,正常城市也是如此.且在1号城市和N号城市,小A不需要住店. 现询问从1号城市到N号城市所需要的最小花

BZOJ 1698 [Usaco2007 Feb]Lilypad Pond 荷叶池塘 BFS+最短路

题意:链接 **方法:**BFS+最短路 解析: 这道题还是挺有意思的. 第一个想法被卡,第一发是二分+bfs,但是这样的话,会有什么处理不了呢?到一个点的流量. 所以就得换想法. 不妨重新定义最短路. 把图中所有的0的点看做可行点,每一次搜出从该点可以到打的0点,然后将这个边权视作1. 即f[i][j]代表到i,j这点的最短路. 显然终点特判: 然后同时记录一下最短路的数量即可. 代码: #include <queue> #include <cstdio> #include &l

hdu 1728 逃离迷宫 (BFS)

逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 14376    Accepted Submission(s): 3458 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方