邮递员送信——最短路

邮递员送信——最短路

有一个邮递员要送东西,邮局在结点 1。他总共要送 N-1 样东西,其目的地分别是 2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 M 条道路,通过每条道路需要一定的时间。 这个邮递员每次只能带一样东西。 求送完这 N-1 样东西平且最终回到邮局最少需要多少时间。

输入格式:

输入文件第一行包含一个正整数 N 和 M;
接下来 M 行, 每行三个正整数 U、 V、 W, 表示该条道路为从 U 到 V 的, 且通过这条道路
需要 W 的时间。满足 1≤U, V≤N,1≤W≤10000, 输入保证任意两点都能互相到达。

输出格式:

输出仅一行,包含一个整数,为最少需要的时间。

限制:

对于 30%的数据,满足 1≤N≤200。
对于 100%的数据,满足 1≤N≤1000,1≤M≤100000。

样例 1 :

输入:
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
输出:
83

解题思路:

这道题我一开始是用Floyd写的,只能通过部分数据,然后其他数据超时。然后想了很长时间还是没想出来(可能是智商问题吧

~_~)。然后我看了一些大佬的代码,终于懂了,就是用两次Dijkstra算法,这个题意思是求起点到每个点的最短距离,然后再求每个点到起点的距离。最后输出这些距离的和。(还是一道水题);

下面看代码:

#include <stdio.h>
int a[1001][1001];
int dis[1001],book1[1001];//book1,book2用来标记; 
int book2[1001]; 

int main()
{
	int n,m,u,v,w,i,t,j,inf=99999999,sum=0,min,tt;
	
	scanf("%d%d",&n,&m);//输入数据 
	for(i=1;i<=n;i++)//建图 
		for(j=1;j<=n;j++)
			if(i==j) a[i][j]=0;
			else a[i][j]=inf;
			
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		if(a[u][v]>w)//注意这里,数据有重边的 
			a[u][v]=w;
	}
	for(i=1;i<=n;i++)//初始化dis数组 
		dis[i]=a[1][i];
		
	
	book1[1]=1;//标记起点 
	//核心,Dijkstra算法 
	for(i=1;i<=n-1;i++)//送信 
	{
		min=inf;
		for(j=1;j<=n;j++)
		{
			if(min>dis[j]&&book1[j]==0)//找出距离起点最近的点 
			{
				min=dis[j];
				t=j;
			}
		}
		book1[t]=1;//标记这个点 
		for(j=1;j<=n;j++)//寻找距离t点最近的点 
		{
			if(a[t][j]<inf)
				if(dis[j]>dis[t]+a[t][j])
				{
					dis[j]=dis[t]+a[t][j];
				}
					
		}
	}
	for(i=1;i<=n;i++)
		if(dis[i]!=inf) sum+=dis[i];//将送信所用时间加起来 
		
	book2[1]=1;//再次执行Dijkstra算法,回邮局 
	for(i=1;i<=n;i++)//先将图翻转 
		for(j=1;j<i;j++)
		{
			tt=a[i][j];
			a[i][j]=a[j][i];
			a[j][i]=tt;
		}
	
	for(i=1;i<=n;i++)//数据初始化 
		dis[i]=a[1][i];
	
	for(i=1;i<=n-1;i++)
	{
		min=inf;
		for(j=1;j<=n;j++)
		{
			if(min>dis[j]&&book2[j]==0)
			{
				min=dis[j];
				t=j;
			}
		}
		book2[t]=1;
		for(j=1;j<=n;j++)
		{
			if(a[t][j]<inf)
				if(dis[j]>dis[t]+a[t][j])
					dis[j]=dis[t]+a[t][j];
		}
	}
	for(i=1;i<=n;i++)
		if(dis[i]!=inf) sum+=dis[i];//把回邮局用的时间加起来 

	printf("%d\n",sum);
	return 0;
	
}

测题网站:https://www.acoj.com/problems/12084

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值