最短路反向建边问题

在今天的限时训练中遇到了一道有意思的最短路问题,现在来跟大家分享一下。

题意:

One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the big cow party to be held at farm #X (1 ≤ X ≤ N). A total of M (1 ≤ M ≤ 100,000) unidirectional (one-way roads connects pairs of farms; road i requires Ti (1 ≤ Ti ≤ 100) units of time to traverse.

Each cow must walk to the party and, when the party is over, return to her farm. Each cow is lazy and thus picks an optimal route with the shortest time. A cow's return route might be different from her original route to the party since roads are one-way.

Of all the cows, what is the longest amount of time a cow must spend walking to the party and back?

Input

Line 1: Three space-separated integers, respectively: NM, and X
Lines 2..M+1: Line i+1 describes road i with three space-separated integers: AiBi, and Ti. The described road runs from farm Ai to farm Bi, requiring Ti time units to traverse.

Output

Line 1: One integer: the maximum of time any one cow must walk.

Sample Input

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

Sample Output

10

题目大意:有n头牛分布在图中不同位置,图中有一个农场,现在给你不同点之间的路线及其时间花费,注意路线是单向的,让你求所有牛中从自己原来位置到农场后再返回自己家所需要的时间中的最小值。

分析:我们的目标不仅仅是求每头牛到农场的最短时间,还要求每头牛从农场返回到自己原来位置的最小时间,两个时间加到一块求个最小值就行。

容易想到我们求牛从农场回到自己家的最短时间比较容易,只需要以农场作为起点,跑一个最短路就行,关键是我们怎么求出从牛原来的位置到农场的最短时间,这个时候我们就需要用到反向建边的技巧了,换位思考一下,如果我们反向建边,牛从自己原来位置走到农场的路线不就相当于从农场走到牛原来的位置么。那我们不就又可以以农场作为起点跑最短路了么,思路就是这样,详情看代码!

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
const int N=1003;
//d1[i]用于存第i号牛从农场返回的最短时间,而d2[i]存第i号牛去农场的最短时间 
int h[N],d1[N],d2[N],ne[N],e[N],idx;
bool vis[N];
int w1[N][N],w2[N][N];
int n,m,x;
void spfa1()
{
	queue<int> q;
	memset(vis,false,sizeof vis);
	memset(d1,0x3f,sizeof d1);
	d1[x]=0;
	q.push(x);
	while(q.size())
	{
		int begin=q.front();
		q.pop();
		vis[begin]=false;
		for(int j=1;j<=n;j++)
		{
			if(d1[j]>d1[begin]+w1[begin][j])
			{
				d1[j]=d1[begin]+w1[begin][j];
				if(!vis[j])
				{
					vis[j]=true;
					q.push(j);
				}
			}
		}
	}
}
void spfa2()
{
	queue<int> q;
	memset(vis,false,sizeof vis);
	memset(d2,0x3f,sizeof d2);
	d2[x]=0;
	q.push(x);
	while(q.size())
	{
		int begin=q.front();
		q.pop();
		vis[begin]=false;
		for(int j=1;j<=n;j++)
		{
			if(d2[j]>d2[begin]+w2[begin][j])
			{
				d2[j]=d2[begin]+w2[begin][j];
				if(!vis[j])
				{
					vis[j]=true;
					q.push(j);
				}
			}
		}
	}
}
int main()
{
	cin>>n>>m>>x;
	int a,b,c;
	memset(w1,0x3f,sizeof w1);
	memset(w2,0x3f,sizeof w2);
	for(int i=1;i<=n;i++) w1[i][i]=w2[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		w1[a][b]=min(w1[a][b],c);
		w2[b][a]=min(w2[b][a],c);//反向建边 
	}
	int ans=0;
	spfa1();spfa2();
	for(int i=1;i<=n;i++) ans=max(ans,d1[i]+d2[i]);
	printf("%d",ans);
	return 0;
}

现在我来对最短路 起点终点个数不同的情况作下分析:

(1)1个起点        1个终点

这种的是最简单的,就直接跑一个最短路即可

(2)一个起点       多个终点

两种做法:第一种思路是利用起点直接跑最短路,然后对终点一个一个遍历求最值即可,第二种思路就是建立一个超级源点,然后将每个终点向超级源点加一条权值为0的边,然后求起点到超级源点的最短距离即可。

(3)多个起点       1个终点

两种做法:第一种思路就是建立一个超级源点,然后用超级源点与所有起点连一条权值为0的边,转化为1个起点,1个终点的问题。   第二种思路就是我们一开始就反向建边,然后就变成了一个起点多个终点的问题了。

(4)多个起点       多个终点

我们可以建立一个超级源点,然后利用这个超级源点与所有起点各连一条边转化为1个起点多个终点问题,还可以用所有终点与超级源点各连一条边转化为多个起点一个终点的问题,也可以建立两个超级源点分别同起点和终点进行建边从而转化为一个起点一个终点的问题。

以上就是我对最短路不同起点不同终点问题的处理方法了,如果大家有更好的方法,欢迎在评论区里分享。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值