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

输出格式:

一个整数表示最低花费

输入输出样例
输入样例#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


先搜索出危险的城市,然后跑spfa(近乎于模板题)。
注意:
1 要用long long。
2 dfs时要用到spfa的思想,不是搜过就不搜,而是如果可以更新还要搜索。
3 关于cst数组 如果边搜索边赋值,有可能给n赋了值。


#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<queue>
using namespace std;
const long long inf=1000000000ll*1000000000ll+10ll;
const int maxn=100005;
vector<int>v[maxn];
queue<int>que;
int n,m,k,s,stp[maxn],c[maxn];
long long p,q,dis[maxn],cst[maxn];
bool b[maxn],inq[maxn];//b[]是不能到达
void dfs(int u)
{
    if(stp[u]==s)
        return ;
    for(int i=0;i<v[u].size();i++)
        if(!b[v[u][i]]&&stp[v[u][i]]>stp[u]+1)
        {
            stp[v[u][i]]=stp[u]+1;
            cst[v[u][i]]=q;
            dfs(v[u][i]);
        }
}
void spfa()
{
    for(int i=1;i<=n;i++)
        dis[i]=inf;
    que.push(1);
    inq[1]=1;
    dis[1]=0;
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        inq[u]=0;
        for(int i=0;i<v[u].size();i++)
            if(!b[v[u][i]])
                if(dis[v[u][i]]>dis[u]+cst[v[u][i]])
                {
                    dis[v[u][i]]=dis[u]+cst[v[u][i]];
                    if(!inq[v[u][i]])
                    {
                        que.push(v[u][i]);
                        inq[v[u][i]]=1;
                    }
                }
    }
    printf("%lld\n",dis[n]);
}
int main()
{
    scanf("%d%d%d%d%lld%lld",&n,&m,&k,&s,&p,&q);
    for(int i=2;i<=n-1;i++)
        cst[i]=p;
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&c[i]);
        b[c[i]]=1;
    }
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    memset(stp,0x3f,sizeof(stp));
    for(int i=1;i<=k;i++)
    {
        stp[c[i]]=0;
        dfs(c[i]);
    }
    cst[n]=0;
    spfa();
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值