POJ-3682-Silver Cow Party问题(Dijkstra算法求解)


Silver Cow Party问题

题目

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: N, M, and X
Lines 2… M+1: Line i+1 describes road i with three space-separated integers: Ai, Bi, 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

Hint
Cow 4 proceeds directly to the party (3 units) and returns via farms 1 and 3 (7 units), for a total of 10 time units.

初步探索算法思路

刚接触这道题时,第一反映是使用多源最短路径的Floyd算法,在最短路的二维数组中寻找哪个点到目标点的距离最长,但是时间复杂度为O(n3),明显会超时,因此需要考虑其他算法。

正确算法思路

我们需要将这个题进行分解成两个过程:

1、前往:首先求出由其他各点到目标点x的最短路径(这个过程为每头奶牛从农场出发到达目标农场的最短路径)
2、回家:每头奶牛回家的过程,即为从目标点x回到其他各点的过程(这个过程为从目标农场出发到达每头奶牛出发时的农场)

第一阶段“前往”,可以使用Dijkstra算法或者Bellman_Ford算法(这里我使用Dijkstra算法
第二阶段“回家”,我们换个思路,从目标农场回到家中,即反向从家中到达目标农场,只是此时每两个农场间的路进行交换,即将各条单向路径的方向调转,也就是本来从农场1到农场2的路径,变成农场2到农场1的路径。然后再次使用第一阶段的算法再求一次各点最短路径
在这里插入图片描述

最后将两个阶段的最短路径加和后从中选择最长的路径即为本题解
在这里插入图片描述

解题代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 99999999	//设置无穷大 
using namespace std;

int N,M,X;
int e[10005][10005];	//带权值的邻接矩阵 
int book[10005];        //记录该节点是否为已为最短路径 
int dis[10005];		//总最短路径 
int dis1[10005];	//第一阶段最短路径 
int dis2[10005];	//第二阶段最短路径 

//邻接矩阵初始化函数 
int enit() 
{
	for(int i=1;i<=N;i++)
		for(int j=1;j<=N;j++)
			if(i==j)
				e[i][j]=0;
			else
				e[i][j]=INF;
}

//Dijkstra算法函数 
void Dijkstra(int dis[])
{
	memset(book,0,sizeof(book));	//将book数组中所有元素置为0 
	for(int i=1;i<=N;i++)	//dis数组初始化 
		dis[i]=INF;
	book[X]=1;	//出发农场的必为最短距离且距离为0 
	
	//首先初始化点X到所有点的最短距离为X与此点的邻接边 
	for(int i=1;i<=N;i++)
		dis[i]=e[X][i]; 
	
	//从最短路径数组中每次选择最小路径权值的节点,可以保证每次更新路径最终为最短路径 
	for(int i=1;i<=N;i++){
		int min=INF;
		int mark;
		for(int j=1;j<=N;j++)
			if(book[j]==0&&min>dis[j]){
				min=dis[j];
				mark=j;
			}
		book[mark]=1;	//找到最小权值的节点,并认为其已为最短路径 
		
		//用最小权值节点去更新其他节点的最短路径 
		for(int j=1;j<=N;j++)
			if(e[mark][j]<INF)	
				if(dis[j]>dis[mark]+e[mark][j])
					dis[j]=dis[mark]+e[mark][j];
	}
}

//转置邻接矩阵函数 
int exchange()
{
	for(int i=1;i<=N;i++)
		for(int j=i+1;j<=N;j++)
				swap(e[i][j],e[j][i]);
}

int main()
{
	scanf("%d %d %d",&N,&M,&X);
	
	enit();
	
	//输入数据,并存入邻接矩阵 
	int from,to,cost;
	for(int i=0;i<M;i++){
		scanf("%d %d %d",&from,&to,&cost);
		e[from][to]=cost;
	}			

	Dijkstra(dis1);	//未转置前调用一次	
	exchange();		//转置邻接矩阵 
	Dijkstra(dis2);	//转置后调用一次 
	
	//将两次最短路径结果加和 
	for(int i=1;i<=N;i++)
		dis[i]=dis1[i]+dis2[i];
	
	//寻找最终最短路径数组中的最大权值 
	int max=-1;
	for(int i=1;i<=N;i++)
		if(max<dis[i])
			max=dis[i];
	
	printf("%d",max);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

省下洗发水钱买书

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

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

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

打赏作者

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

抵扣说明:

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

余额充值