シルバーカウパーティー(シングルソース最短経路:片道の最短経路の使用)

トピック1:このトピックのリンクを送信します。このトピックは、頂点が少ない隣接行列で記述できます。
トピック2:リンクを送信します。このトピックは隣接リストで記述しなければなりません。頂点が多すぎます。

Nの農場(1≤N≤1000)のそれぞれから1頭の牛が1…Nと番号が付けられ、農場#X(1≤X≤N)で開催される大きな牛のパーティーに参加します。合計M(1≤M≤100,000)の一方向(一方通行の道路が農場のペアを接続します。道路iは、通過するのにTi(1≤Ti≤100)単位の時間を必要とします。

各牛はパーティーまで歩いて行き、パーティーが終わったら農場に戻らなければなりません。各牛は怠惰であるため、最短時間で最適なルートを選択します。牛の帰りのルートは、道路が片道であるため、元のパーティーへのルートとは異なる場合があります。

すべての牛の中で、牛がパーティーまで歩いて戻ってくるのに費やす必要のある最長の時間はどれくらいですか?

入力
ライン1:それぞれ3つのスペースで区切られた整数:N、M、およびX
ライン2…M + 1:ラインi + 1は、3つのスペースで区切られた整数(Ai、Bi、およびTi)を持つ道路iを表します。説明されている道路は、農場Aiから農場Biまで走っており、Ti時間単位で横断する必要があります。
出力
行1:1つの整数:1頭の牛が歩かなければならない最大時間。

サンプル入力

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

サンプル出力

10

ヒントカウ
4は直接パーティー(3ユニット)に進み、ファーム1と3(7ユニット)を経由して合計10時間ユニットに戻ります。

タイトルの意味:
1からnまでの番号が付けられたnの農場で、各農場は農場xで開催されるパーティーに牛を送ります。すべての牛は怠惰で、最短の合計時間を前後に過ごしたいと思っています(もちろん、どれだけ短いかは、行くときの時間が短く、戻ってくるときの時間が短くなります)。現在のニーズはすべての牛の外にあります。 、および前後の総コストは次のとおりです。最も時間がかかる牛が費やした時間
注:片道側、前後の距離は同じではない場合があります

アイデア:
単一ソースの最短パス、2回使用、
1。最初に頂点xから各頂点へ
の最短パスを見つけます2.次に各頂点からxへの最短パスを見つけます(実際には、すべてのエッジを反転して最短を見つけるだけです。再び各頂点への道X)。
あなたは、コードを理解していない場合:なるほどアルゴリズム帳を参照してください
コードを

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;

int e[1100][1100];
int book[1100];//book[i]标记为1,说明顶点i到源点的最短路已确定,即dis[i]不可能更小的了,若book[i]标记仍为0,说明此刻的dis[i]还有可能变得更小。
int dis[1100];//用来存储源点到各个点的距离
int dis1[1100];
int n,m,x;
/* 
e[i][j]用来存储顶点i到顶点j的距离,
规定顶点i到其本身的距离为0,
规定顶点i不能直接到达顶点j的距离为无穷大

数组book,book[i]==1表示顶点i不得再被使用,
book[i]==0表示顶点i可以被使用 

数组dis1,用来存放x到各个点的最小距离
数组dis,用来存放各个点到x的最小距离

*/
void Dijkstra()
{
	int i,j;
	memset(book,0,sizeof(book));//全部是估计值
	book[x]=1;//x到x的距离最短 
	// 
	for(i=1;i<=n;i++)///最初dis数组中存放的是x直接到任意一个点的最小值,
		dis[i]=e[x][i];/而不是任意两点的最小值 

	int minn,u,v;
	for(i=1;i<=n-1;i++)//为什么这里最多循环为n-1次,那是因为源点到源点本身最短路肯定为0,剩下(n-1)个顶点到源点的距离才是我们要求的,而每一次循环我们一定确定一个顶点的最短路,为什么呢,看下面的解释
	{
		minn=inf;
		u=-1;
	
		for(j=1;j<=n;j++)//寻找离源点到最近的一个点 
		{
			if(!book[j]&&minn>dis[j])//book[j]==1表明dis[j]已经确定过了,是最短的
			{
				minn=dis[j];
				u=j;
			}
		}
		/*
       这里说说为什么找到了离源点最近的顶点u,就一定可以确定u到源点的最短路了,为什么不能再通过别的路使得源点到u的距离变的更短了,首先你要明白,我们每次都是寻找的就是离源点的最近的顶点,所以当然不可能存在比该路更短的路了。你还要明白,此刻的u不一定是和源点直接相连的顶点,有可能是了经过很多顶点才到达顶点u的,但无论经过多少顶点到达u的,这条源点到u的路一定是最短的,可以相当于贪心,每次都是寻找最短,最短从而得到最短
        */
		if(u==-1)
			break;
		/*
		这里为什么要加一个跳出循环的操作呢,那是因为,这里的(n-1)次循环我们其实假设的是源点一定可以到其它(n-1)个顶点(无论是直接到达,还是间接到达)。但有些样例可能存在源点永远不可能到达的顶点,假设只有n-5个顶点与源点相连,那么其实我们只循环n-5次就可以了,所以这里才会加一个提前跳出的操作
		*/
		book[u]=1;//dis[u]最短,不可能再小了
		for(v=1;v<=n;v++)//寻找与u相连的顶点v,利用顶点u,看是否可以使源点到v的距离更短,即能否使dis[v]更小
		{
			if(!(book[v]||e[u][v]<inf))//表明u与v有路,dis[v]有可能变小,或者,若book[v]==0,dis[v]也有可能变小。
			{
				if(dis[v]>dis[u]+e[u][v])//是否可使dis[v]更小
					dis[v]=dis[u]+e[u][v];
			}
		}
	}
}
int main()
{
	int i,j,u,v,w,t;
	while(~scanf("%d %d %d",&n,&m,&x))
	{
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				if(i==j)	e[i][j]=0;
				else 		e[i][j]=inf;
		for(i=1;i<=m;i++)
		{
			scanf("%d %d %d",&u,&v,&w);
			e[u][v]=min(w,e[u][v]);//单向边,可能有重边 
		}
		Dijkstra();
	
		for(i=1;i<=n;i++)
			dis1[i]=dis[i];
	
		/*
		源点x到别的点的最短路已求出,
	
		因为是单向边,因此二者往返很可能不是一条路
		那该怎么求别的点到源点x的最短路
	
		只需将给出的边方向翻转再使用Dijkstra(x),仔细想想,因为原本可以走的路现在因为边翻转的缘故,已经不能走了,x若还想到达其它点,其实走的路便是其它点到x所走的路 
	
		*/ 
	
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
			{
				t=e[i][j];//边翻转,不能覆盖 
				e[i][j]=e[j][i];
				e[j][i]=t;
			}
		}
		
		Dijkstra();
	
		int maxx=-inf;
		for(i=1;i<=n;i++)
			if(dis[i]<inf&&dis1[i]<inf)
				maxx=max(maxx,dis[i]+dis1[i]);
		printf("%d\n",maxx);
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/Helinshan/article/details/109919967