luogu P3393 逃离僵尸岛

题目描述

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

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

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

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

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

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

输入格式

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

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

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

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

输出格式

一个整数表示最低花费


首先我们需要知道哪些城市是危险的:

根据广搜的性质(第一次搜到的答案就是最优值),我们将被占领的城市入队,然后用广搜将它们拓展从而求出与最近被占城市距离在S以内的城市。

然后我们需要计算最短路:

安全的城市点权就是P,危险的就是Q,而被占领的城市不能去,干脆让点权变成inf。然后用Dijkstra即可。

时间复杂度为O((N+M)log(N+M))。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 100001
#define maxm 200001
#define inf 0x3f3f3f3f
using namespace std;
int n,m,K,S,P,Q;
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

struct edge{
    int to,next;
    edge(){}
    edge(const int &_to,const int &_next){ to=_to,next=_next; }
}e[maxm<<1];
int head[maxn],k;
inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }

int val[maxn];
bool vis[maxn];
queue< pair<int,int> > que;
inline void bfs(){
    while(que.size()){
        int u=que.front().first,w=que.front().second; que.pop();
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(!vis[v]&&w+1<=S) que.push(make_pair(v,w+1)),vis[v]=true;
        }
    }
}

long long dis[maxn];
bool used[maxn];
priority_queue< pair<long long,int>,vector< pair<long long,int> >,greater< pair<long long,int> > > q;
inline void Dijkstra(){
    memset(dis,0x3f,sizeof dis);
    q.push(make_pair(0,1)),dis[1]=0;
    while(q.size()){
        int u=q.top().second; q.pop();
        if(used[u]) continue; used[u]=true;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(dis[v]>dis[u]+val[v]) dis[v]=dis[u]+val[v],q.push(make_pair(dis[v],v));
        }
    }
}

int main(){
    memset(head,-1,sizeof head);
    n=read(),m=read(),K=read(),S=read(),P=read(),Q=read();
    for(register int i=1;i<=K;i++){
        int x=read();
        que.push(make_pair(x,0)),val[x]=inf,vis[x]=true;
    }
    for(register int i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    bfs();
    
    for(register int i=1;i<=n;i++){
        if(vis[i]&&!val[i]) val[i]=Q;
        if(!vis[i]) val[i]=P;
    }
    val[1]=val[n]=0;
    Dijkstra();
    printf("%lld\n",dis[n]);
    return 0;
}
posted @ 2019-06-22 09:18  修电缆的建筑工  阅读(186)  评论(0编辑  收藏  举报