luoguP3393逃离僵尸岛

题目描述

小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,表示一条无向边

输出格式:

一个整数表示最低花费

输入输出样例

输入样例#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
输出样例#1: 复制
11000

说明

对于20%数据,N<=50

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

1 ≦ P < Q ≦ 100000
分析
思路很简单就是做两遍最短路,第一次求出边权;第二次就是求出最小值;不过要注意开long long
卡点
被卡了7次啊ovo;我现在才发现我原来的最大值的赋值一直都是有问题的,那么我想到了原来的比赛我一直炸零是不是因为赋值的问题啊QwQ
#include<bits/stdc++.h>
#define N 100005
#define M 200005
#define INF 1e18
using namespace std;
struct edge{int Next,vet;}g[M<<1];
int tot,head[N];
void add(int x,int y){
    tot++;
    g[tot]=((edge){head[x],y});
    head[x]=tot;
}//邻接表
int n,m,k,s,Q,P;
long long d[N];
int inq[N],c[N];
void SPFA(){//第一遍初始化权值
    queue <int> q;
    for(int i=1;i<=n;i++)d[i]=INF;
    for(int i=1;i<=k;i++){
        d[c[i]]=0;
        inq[c[i]]=1;
        q.push(c[i]);
    } //从所有的危险节点扩展
    while(!q.empty()){
        int u=q.front();q.pop();
        inq[u]=0;
        for(int i=head[u];i;i=g[i].Next){
            int v=g[i].vet;
            if(d[v]>d[u]+1){
                d[v]=d[u]+1;
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                }
            }
        } 
    }
}//标准写法详见之前的模板题解
long long w[N];
void spfa(){
    queue <int> q;
    for(int i=1;i<=n;i++){
        if(d[i]<=s)w[i]=Q;else w[i]=P;
        d[i]=INF;
    }//初始化
    for(int i=1;i<=k;i++)w[c[i]]=INF;//注意这点很重要危险的城市是不能访问的,我不清楚luogu的题解是怎么不写这句话过的,如果你发现了请联系我
    inq[1]=1;
    d[1]=w[n]=w[1]=0;//起点和终点没有权值
    q.push(1);
    while(!q.empty()){
        int u=q.front();q.pop();
        inq[u]=0;
        for(int i=head[u];i;i=g[i].Next){
            int v=g[i].vet;
            if(d[v]>d[u]+w[u]){
                d[v]=d[u]+w[u];
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                }
            }
        } 
    }
}//同样标准写法
int main(){
    scanf("%d%d%d%d",&n,&m,&k,&s);
    scanf("%d%d",&P,&Q);
    for(int i=1;i<=k;i++)scanf("%d",&c[i]);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }//连边
    SPFA();
    spfa();
    cout<<d[n];//输出解决格式问题
    return 0;
}
心得
注意到最大值的赋值问题而且做题目的时候要注意题干而去推算最大值最好出一组大数据去验证一下至少不要爆内存QAQ;还有就是说SPFA的写法比Bell-mam的写法的另一好处就是可以结合宽搜直接嗯从多个节点扩展
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值