Silver Cow Party (dijk)

本文介绍如何使用Dijkstra算法解决寻找从特定农场出发,参加派对并返回的奶牛所需的最大时间问题。该问题涉及到单向路径的最短路径计算,需要两次运行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 ≤ XN). 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?

翻译:

来自 n 个农场(1≤n≤1000)的1. .n头奶牛将参加农场 x(1≤x≤n)举办的大型奶牛派对。共有m(1≤m≤100000)单向(单向道路连接成对农场);i 号公路需要 Ti(1≤Ti≤100)单位的穿越时间。
每头牛都必须走到派对上,派对结束后,回到自己的农场。每头母牛都懒惰,因此选择了一条时间最短的最佳路线。一头牛的返回路线可能不同于她最初去派对的路线,因为道路是单向的。
在所有的奶牛中,一头奶牛步行去聚会和回来必须花多长时间?

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.

翻译:

第1行:三个空格分隔的整数,分别为:n、m和x
第2…M+1行:第 i+1行用三个空格分隔的整数(ai、bi和ti)描述了道路I。所描述的道路从农场ai到农场bi,需要Ti时间单位进行穿越。

output

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

第1行:一个整数:任何一头牛必须行走的最长时间。

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.

翻译:

奶牛4直接进入一方(3个单位),通过农场1和3(7个单位)返回,总共10个时间单位。

一个比较基础的dijkstra 算法问题,就是要注意他是要求的是一来一回的总共最大时间,而且路都是单向的。先计算x农场到其他农场用的最短时间,在枚举其他农场到x农场的最短时间,记录下最大来回时间。但是要注意时间复杂度,小心超时,所以我这里用了一个转置矩阵,交换 map[i][j] 与 map[j][i] 的值,这样就能避免超时。

代码如下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf= 99999999;
int dis1[1111],dis[1111],map[1111][1111],visit[1111];
int m,n,x,a,b,t,i,j,k,minx,temp,v,ans=0;
void dijkstra()
{
	memset(visit,0,sizeof(visit));       //初始化visit数组 
	for(i=1;i<=n;i++)
	    dis[i]=map[x][i];      //初始化 
	visit[x]=1;
	v=x;
	for(k=2;k<=n;k++)                     //求出距离x  最近的一个 牛场 并记录下来 
	{
		minx=inf;
		for(j=1;j<=n;j++)
		{
			if(!visit[j]&&dis[j]<minx)
		  {
			minx=dis[j];
			v=j;
		   }
		}
		visit[v]=1;
		for(i=1;i<=n;i++)              //求出各个 牛场  到x  的最短距离 
		    if(!visit[i]&&dis[i]>dis[v]+map[v][i])
		        dis[i]=dis[v]+map[v][i];
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&x);     //输入 
	for(i=1;i<=n;i++)                 //将数组map 初始化 
	    for(j=1;j<=n;j++)
	   {
	   	    if(i==j)
	   	        map[i][j]=0;
	   	    else
	   	        map[i][j]=inf;
	   }
	for(i=0;i<m;i++)            //输入道路信息,并储存在map中 
    {
    	scanf("%d%d%d",&a,&b,&t);
    	if(t<map[a][b])
    	map[a][b]=t;
	}
	dijkstra();   //第一次调用,得出x  到 其他牛场的最短时间 
	for(i=1;i<=n;i++)   //储存第一次调用得到的值 
	   dis1[i]=dis[i];
	for(i=1;i<=n;i++)     //最重要的!!转置矩阵,也就是交换map[i][j]与map[j][i]的值 
	    for(j=i+1;j<=n;j++)   //相当于把求其他农场到x  的距离   转换成了求  x  到其他牛场的距离 
	    {
		    temp=map[i][j];
		    map[i][j]=map[j][i];
		    map[j][i]=temp;
	    }
	dijkstra();        //第二次调用 ,再求 x 到其他牛场的距离 
	for(i=1;i<=n;i++)
	   if(i!=x)
	        ans=max(ans,dis1[i]+dis[i]);     //求出两次调用结果之和最大 
	printf("%d\n",ans);         //输出 
	return 0;
}
### 带权邻接矩阵在Dijkstra算法中的实现 #### 邻接矩阵表示方法 为了有效地处理加权图,通常采用邻接矩阵来表示图。对于一个具有`n`个节点的图而言,其邻接矩阵是一个大小为`n×n`的二维数组,在该数组中,如果存在一条从节点i到j权重为w(i,j)的边,则设置matrix[i][j]=w(i,j),否则设为无穷大(即不可达状态),这可以通过宏定义`INT_MAX`来表示[^1]。 ```cpp #include <climits> #define INF INT_MAX typedef double MAT[MaxSize][MaxSize]; ``` #### 初始化操作 初始化阶段需设定源点至自身的距离为0,并将其余所有顶点的距离初始化为无穷大;同时创建一个布尔型访问标记数组visited[]用于记录哪些顶点已被加入到了最短路径树中[^3]。 ```cpp void Init(MGraph G, int dist[], bool visited[]) { for (int i = 0; i < G.vexnum; ++i){ dist[i] = G.edges[source][i]; visited[i] = false; } visited[source] = true; } ``` #### 主循环逻辑 核心部分在于不断选取未被访问过的最近邻居作为新的起点更新其他可达结点之间的最短距离直到遍历完所有的顶点为止。每次迭代过程中都会选出尚未处理过且离已知集合最近的一个顶点u并把它纳入SPT(Shortest Path Tree)内,接着通过它尝试松弛那些由u可以直接抵达却还未收录进来的候选者v们所对应的估计值d[v]。 ```cpp for(int count=2;count<=G.vexnum;++count){ //除了起始点外还需要选V-1次 minDist = INF; u=-1; /* 寻找下一个要加入SPT集的顶点 */ for(v=0; v<G.vexnum ;++v) if(!visited[v] && dist[v]<minDist){ u=v; minDist=dist[v]; } visited[u]=true; /* 更新其它相邻顶点的距离 */ for(v=0;v<G.vexnum;++v) if(!visited[v] && G.edges[u][v]!=INF && dist[u]+G.edges[u][v]<dist[v]) dist[v]=dist[u]+G.edges[u][v]; } ``` 此过程重复执行直至所有顶点都被包含进来或者不存在更近的选择位置时结束整个流程。最终得到的结果就是从指定起点出发前往各个终点间的最优解向量表。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力的小朱同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值