牛客-雪拉比的求救(最短路+思维)

链接:https://ac.nowcoder.com/acm/contest/6106/I
来源:牛客网
 

题目描述

爱与正义的火箭队为了得到雪拉比,于是对它展开了捕捉计划。当雪拉比受到伤害时,它会使用全部能力穿越到1小时之后的时间,并发出了SOS的求救。
小梁在旅行的途中感受到了雪拉比的求救,她跟着雪拉比的求救,来到了一座遗迹,该遗迹的俯视图可看为n\text{n}n个传送点,m\text{m}m条道路所组成的双向连通图,每一条道路都有对应的长度di\text{d}_idi​。
通过心灵指引小梁终于救出了雪拉比。但是由于被火箭队追赶,雪拉比只能隐藏自己的气息。
火箭队也发现了雪拉比和小梁的位置,同时小梁也在雪拉比的帮助下确定了火箭队的位置。小梁想知道在她和火箭队移动速度相同的条件下,为了顺利的躲避火箭队,并且双方都以最短路径向对方原始位置移动,有多少方案可以使得他们不相遇,并对方案数取模109+710^9+7109+7。

输入描述:

第一行输入两个整数N和M(1≤N≤100000,1≤M≤200000)
第二行输入两个整数S和T(1≤S,T≤N,S≠T)分别表示小梁和火箭队所在的位置
下面M行输入三个整数 ui,vi,di表示第ui个点和第vi个点相连,他们的距离是di(1≤ui,vi≤N,1≤di≤10^9)

输出描述:

输出所有符合条件的方案对10^9+7取模后的数。

示例1

输入

 

8 9
4 2
1 2 2
7 6 9
2 8 12
4 2 18
8 4 2
3 5 18
1 5 3
4 7 7
2 7 7

输出

 

2

说明

4和2之间的最短路为14,其中不会相遇的方案路线分别为:
①T到S:2-8-4;S到T:4-7-2
②T到S:2-7-4;S到T:4-8-2

思路:用dijkstra算法求解出,每个点到S的距离 da[0][i] 和到T的距离 da[1][i] ,以及相应的最短路线数 su[0][i] 和 su[1][i] 。

分析可知需要知道S到T的最短路径,以及路径数cnt=da[0][T]。

 如果不考虑相遇则方案数为 sum=cnt*cnt 。

相遇的话则有两种情况:

1.在某一点相遇。方案数为 g=su[0][i]*su[1][i]*su[0][i]*su[1][i] 。

2.在路径上相遇。方案数为 h=su[0][u]*su[1][v]*su[0][u]*su[1][v] 。

最终结果为 sum-g-h 。

AC示例代码

#include <iostream>//超时 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#define cla(a, sum) memset(a, sum, sizeof(a))
#define rap(i, m, n) for(int i=m; i<=n; i++)
#define rep(i, m, n) for(int i=m; i>=n; i--)
#define bug printf("???\n")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> P;
const ll Inf = 1e17;
const double eps = 1e-8;
const int maxn = 1e5+5;
const ll MOD=1e9+7;
template <typename T> void read(T &x){
    x = 0; int f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}

int n,m;
int s,t;
int a[maxn],cnt;
struct node{
	ll d;
	int id,next;
}f[4*maxn];
int vis[2][maxn]={0};
ll da[2][maxn],su[2][maxn];
ll sum;

void init(){
	cla(a,-1);
	rap(i,0,n){
		da[0][i]=da[1][i]=Inf;
	}
	cnt=0;
}

void add(int u,int v,ll d){
	f[cnt].id =v;
	f[cnt].d =d;
	f[cnt].next =a[u];
	a[u]=cnt++;
}

void dijk(int x,ll d[],int ok[],ll sa[])
{
	priority_queue<P>p;
	p.push(make_pair(0,x));
	sa[x]=1;d[x]=0;
	while(!p.empty() ){
		int u=p.top().second;
		p.pop() ;
		if(ok[u])continue; 
		ok[u]=1;
		for(int i=a[u];i!=-1;i=f[i].next ){
			int c=f[i].id ;
			if(d[c]>d[u]+f[i].d ){
				d[c]=d[u]+f[i].d ;
				sa[c]=sa[u]%MOD;
				p.push(make_pair(-d[c],c)); 
			}else if(d[c]==d[u]+f[i].d ){
				sa[c]=(sa[u]+sa[c])%MOD;
			}
		} 
	} 
}

int main()
{
    read(n);read(m);
	init();
    cin>>s>>t;
    int u,v;
	ll d;
    rap(i,1,m){
    	scanf("%d%d%lld",&u,&v,&d);
    	add(u,v,d);
    	add(v,u,d);
	}
	dijk(s,da[0],vis[0],su[0]);
	dijk(t,da[1],vis[1],su[1]);
	sum=su[0][t]*su[1][s]%MOD;
//	cout<<sum<<endl;
	d=da[0][t];
	rap(i,1,n){
		if(da[0][i]==da[1][i]&&2*da[0][i]==d){//在某点相遇 
	        sum=sum-(su[0][i]*su[1][i]%MOD)*(su[0][i]*su[1][i]%MOD)%MOD;
	        sum=(sum+MOD)%MOD;
		} 
		for(int k=a[i];k!=-1;k=f[k].next ){
			u=f[k].id ;
			//在路径上相遇 ,注意d可能为奇数 
			if(da[0][i]+da[1][u]+f[k].d ==d&&da[0][i]<(d+1)/2&&da[1][u]<(d+1)/2){
				sum=sum-(su[0][i]*su[1][u]%MOD)*(su[0][i]*su[1][u]%MOD)%MOD;
				sum=(sum+MOD)%MOD;
			}
		}
	}
	cout<<sum; 
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值