题目描述
小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;
}
谢谢各位