DTOJ 2964 && uoj 52 逃跑(escape)

逃跑(escape)
时间限制: 1 S e c 1 Sec 1Sec 内存限制: 128 M B 128 MB 128MB

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

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

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

输入

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

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

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

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

数据范围

  • 对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 200 1≤n≤200 1n200
  • 对于 另外 20 % 20\% 20% 的数据, S = T S=T S=T
  • 对于 另外 20 % 20\% 20% 的数据, 1 ≤ k ≤ 5 , 1 ≤ n ≤ 1000 , 1 ≤ m ≤ 10000 1≤k≤5,1≤n≤1000,1≤m≤10000 1k5,1n1000,1m10000
  • 对于 100% 的数据, 1 ≤ n ≤ 10000 , 1 ≤ m ≤ 100000 , 1 ≤ k ≤ 10000 , 1 ≤ S , T , u , v ≤ n , 1 ≤ p , q ≤ 1000 1≤n≤10000,1≤m≤100000,1≤k≤10000,1≤S,T,u,v≤n,1≤p,q≤1000 1n10000,1m100000,1k10000,1S,T,u,vn,1p,q1000
    不保证蝙蝠起点互不相等,数据中可能有重边和自环,保证所有点均能走到 T T T 点(即不存在无解情况)。

题解:

很好的一道最短路的应用题。

最朴素的想法:
由于每只蝙蝠的路是少不了的,那么肯定是二小姐先到某个点,然后蝙蝠接着二小姐到终点。于是考虑枚举每一个二小姐与蝙蝠相遇的位置,用最短路求出每只蝙蝠到每个点的最短路,再从起点和终点走一遍即可。

这样显然过不去,考虑优化求蝙蝠的部分。

先求出二小姐到每个点的最短路,和蝙蝠从每个点到终点的最短路。

蝙蝠可能先到其他更远的一个点,再把二小姐接回来,对于这只蝙蝠,要多走的路就是两个位置的最短路之差,于是要让这个差最小。

于是多建一个虚点,从虚点到每个蝙蝠连一条负的最短路的边,这样从虚点往每个点跑的最短路就是多走的路了。

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(re int i=a;i<b;i++)
#define Ford(i,a,b) for(re int i=a;i>b;i--)
#define _(d) while(d(isdigit(ch=getchar())))
template <class T> in void g(T &t) {T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=1e6+4;
#define inf 1e17
typedef long long ll;
struct E{
	int to,nxt,w1,w2;
}e[N<<1];
int n,m,k,s,t,bat[N];bool vis[N];
int head[N],tot;ll d1[N],d2[N],d3[N];
in void ins(int x,int y,int a,int b){
	e[++tot]=E{y,head[x],a,b};head[x]=tot;
}
typedef pair<ll,int>P;
#define mk(a,b) make_pair(a,b)
#define fi first
#define se second 
in void dj(int st,ll *d,int op){
	priority_queue<P,vector<P>,greater<P> >q;
	q.push(mk(0,st));ll dis;
	rep(i,1,n+1) d[i]=inf;d[st]=0;
	memset(vis,0,sizeof(vis));
	while(!q.empty()){
		int x=q.top().se;q.pop();
		if(vis[x]) continue; vis[x]=1;
		for(int i=head[x];i;i=e[i].nxt){
			if(op) dis=e[i].w1;
			else dis=e[i].w2;
			if(d[e[i].to]>d[x]+dis){
				d[e[i].to]=d[x]+dis;
				q.push(mk(d[e[i].to],e[i].to));
			}
		} 
	} 
}
int main(){
	//freopen(".in","r",stdin);freopen(".out","w",stdout);
	g(n),g(m),g(k),g(s),g(t);
	rep(i,1,k) g(bat[i]);
	rep(i,1,m){
		int x,y,a,b;g(x),g(y),g(a),g(b);
		ins(x,y,a,b);ins(y,x,a,b); 
	}
	dj(t,d1,1); dj(s,d2,0);
	rep(i,1,k) ins(n+1,bat[i],-d1[bat[i]],0);
	dj(n+1,d3,1);
	ll ans=inf;
	rep(i,1,n) ans=min(ans,d1[i]+d2[i]+d3[i]);
	rep(i,1,k) ans+=d1[bat[i]];
	printf("%lld\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可爱の小公举

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值