uoj52逃跑(最短路)

题目描述
因为门卫红美玲的失误,疏忽将入侵者放入了红魔馆。入侵者袭击了红魔馆的大小姐蕾米莉亚·斯卡雷特,大小姐在施放【必杀·斯卡雷特家绝技·抱头蹲防】无效后只好变成了好多蝙蝠,在红魔馆中分散开来。

现在的当务之急是找到二小姐芙兰朵露·斯卡雷特,并且与大小姐化身成的所有蝙蝠集合在一点。你的任务就是帮她们找一条最佳路线。

我们可以用一个无向图来表示红魔馆的地图。蝙蝠和二小姐走过任何一条边都要付出一定的代价。因为形态不同,蝙蝠和二小姐走同一条边付出的代价可能不同。但是如果某一只蝙蝠与二小姐碰面,那么二小姐由于蝙蝠的引导,以后的所有路程可以不支付代价。(也就是相当于二小姐和某只蝙蝠都走到某点,之后无视二小姐的存在。)现在已知所有蝙蝠,二小姐和目标集合点的位置,请你求出所有蝙蝠和二小姐行走代价的和的最小值。

输入文件
第一行是55个正整数,n,m,k,S,Tn,m,k,S,T,分别代表无向图点数,边数,蝙蝠的数量,二小姐所在起点的编号,目标点的编号。

第二行是kk个正整数,分别代表大小姐每个蝙蝠所在的起点的编号。

接下来有mm行,每行有44个正整数,u,v,q,pu,v,q,p,分别是该边的起点、终点,蝙蝠通过该路花费的代价,二小姐通过该路花费的代价。

输出文件
一行,一个整数,所有人物达到终点所需要的代价的和的最小值。

样例
[input]
5 5 2 3 4
1 5
1 2 3 5
3 2 3 5
2 4 4 9
3 4 9 6
5 4 1 1

[output]
13
Extra Input Sample

Extra Output Sample

样例解释
11号蝙蝠从 11 到 22,花费 33
二小姐从 33 到 22,花费 55,遇见蝙蝠,之后不计算费用

11 号蝙蝠从 22 到 44,花费 44
22 号蝙蝠从 55 到 44,花费 11
总计 1313
数据约定
对于 30% 的数据,1≤n≤2001≤n≤200
对于 另外20% 的数据, S=TS=T。
对于 另外20% 的数据, 1≤k≤5,1≤n≤1000,1≤m≤100001≤k≤5,1≤n≤1000,1≤m≤10000。

对于 100% 的数据, 1≤n≤10000,1≤m≤100000,1≤k≤10000,1≤S,T,u,v≤n,1≤p,q≤10001≤n≤10000,1≤m≤100000,1≤k≤10000,1≤S,T,u,v≤n,1≤p,q≤1000不保证蝙蝠起点互不相等,数据中可能有重边和自环,保证所有点均能走到 T 点(即不存在无解情况)。


【思路】推出一个式子,求三次最短路,以T为起点的,以S为起点的,以n+1为起点的

【注意】数组大小

【代码】

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define maxn 10004
#define maxm 1000006
#define inf 1000000009
using namespace std;
typedef pair<ll,int>pa;
int n,m,k,s,t,bat[maxn],to[maxm],nxt[maxm],fst[maxn],w1[maxm],w2[maxm],cnt=0;
ll d1[maxn],d2[maxn],d3[maxn],mn;
priority_queue<pa,vector<pa>,greater<pa> >q;
int get(){
    char c;while(!isdigit(c=getchar()));
    int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
    return v;
}
void add(int x,int y,int z1,int z2){to[++cnt]=y;nxt[cnt]=fst[x],fst[x]=cnt,w1[cnt]=z1,w2[cnt]=z2;}
bool vst[maxn];
void dij(int x,ll *d,bool flag){
	ll dis;while(!q.empty())q.pop();
    for(int i=1;i<=n;++i)d[i]=inf;
    memset(vst,0,sizeof(vst));
    d[x]=0;q.push(make_pair(d[x],x));
    while(!q.empty()){
	    int now=q.top().second;q.pop();
	    if(vst[now])continue;
	    vst[now]=1;
	    for(int i=fst[now];i;i=nxt[i]){
			if(!flag)dis=w2[i];
			else dis=w1[i];
		    if(d[to[i]]>dis+d[now]){
			    d[to[i]]=dis+d[now];
			    q.push(make_pair(d[to[i]],to[i]));
			}
		}
	}
}
void init(){
	int u,v,z1,z2;
    n=get(),m=get(),k=get(),s=get(),t=get();
    for(int i=1;i<=k;++i)bat[i]=get();
    for(int i=1;i<=m;++i){
	    u=get(),v=get(),z1=get(),z2=get();
	    add(u,v,z1,z2);
	    add(v,u,z1,z2);
	}
}
void solveit(){
    dij(t,d1,1);dij(s,d2,0);mn=inf;
    for(int i=1;i<=k;++i)add(n+1,bat[i],-d1[bat[i]],0);
    dij(n+1,d3,1);
    for(int i=1;i<=n;++i){
	    mn=min(mn,d1[i]+d2[i]+d3[i]);
	}
	for(int i=1;i<=k;++i)mn+=d1[bat[i]];
	printf("%lld\n",mn);
}
int main(){
    init();
    solveit();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值