逃离僵尸岛【最短路】

题目描述

小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

分析:模板题,找出危险点,点权转边权,地杰斯特拉跑一下就OK。说起来这么轻松,代码实现花了我一天时间,交了10次总算AC,细节见下面的代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,k,s,c[100010],flag[100010];//flag[i]=0,1,2分别表示i号城市安全,危险,被感染
ll dis[100010],p,q;
bool mark[100010];
struct Node
{
    int Num;
    ll dis;
    bool operator<(const Node &a) const
    {
        return a.dis<dis;
    }
};
struct node
{
    int Num;
    ll dis;
};
vector<node> G[100010];
inline void Dij()//地杰斯特拉不解释
{
    priority_queue<Node> q;
    Node temp;
    temp.Num=1;
    temp.dis=0;
    q.push(temp);
    while(!q.empty())
    {
        int u=q.top().Num;
        q.pop();
        if(mark[u]) continue;
        mark[u]=1;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i].Num;
            ll l=G[u][i].dis;
            if(mark[v]==0&&dis[v]>dis[u]+l)
            {
                dis[v]=dis[u]+l;
                temp.Num=v;
                temp.dis=dis[v];
                q.push(temp);
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&s);
    node temp;
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    scanf("%lld%lld",&p,&q);
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&c[i]);
        flag[c[i]]=2;
    }
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        temp.Num=b;
        G[a].push_back(temp);
        temp.Num=a;
        G[b].push_back(temp);
    }
    queue<node> Q;
    for(int i=1;i<=k;i++)
    {
        memset(mark,0,sizeof(mark));//注意每一步都要初始化
        temp.Num=c[i];
        temp.dis=0;//这里的dis表示被感染城市与当前城市的距离
        Q.push(temp);
        while(!Q.empty())//BFS
        {
            int u=Q.front().Num;
            ll l=Q.front().dis;
            Q.pop();
            if(mark[u]==1) continue;//被讨论过就不在讨论了
            mark[u]=1;
            for(int i=0;i<G[u].size();i++)//与这个城市关联的所有边
            {
                int v=G[u][i].Num;
                if(l<s&&mark[v]==0&&flag[v]!=2)//注意标记,不要将被感染城市标记为危险城市
                {
                    flag[v]=1;
                    if(l<s-1)//小优化,可要可不要
                    {
                        temp.Num=v;
                        temp.dis=l+1;
                        Q.push(temp);
                    }
                }
            }
        }
    }
    for(int i=1;i<=n;i++)//给每条边赋值
    {
        for(int j=0;j<G[i].size();j++)
        {
            int v=G[i][j].Num;
            if(v!=1&&v!=n)
            {
                if(flag[v]==0)
                {
                    G[i][j].dis=p;
                }
                else if(flag[v]==1)
                {
                    G[i][j].dis=q;
                }
                else 
                {
                    G[i][j].dis=0x7fffffff;//如果是被感染城市就设置为无穷大(不可到达)
                }
            }
            else
            {
                G[i][j].dis=0;//1号城市和N号城市不住店
            }
        }
    }
    memset(mark,0,sizeof(mark));//注意这里也要初始化
    Dij();
    printf("%lld",dis[n]);//输出
    return 0;
}

谢谢各位

posted @ 2018-05-01 21:00  最爱丁珰  阅读(45)  评论(0编辑  收藏  举报