最短路之floyd题解

① Best Spot 最佳牧场

描述
某头牛有很多喜欢的牧场,现在希望你从这些牧场找出一个最佳的牧场来。别的牧场到这个最佳牧场的最短距离的总和最小。
在这里插入图片描述

输入
第1行输入三个整数P,F C.
之后F行每行输入一个整数表示一个贝茜喜欢的牧场.
之后C行每行输入三个整数ai,bi,Ti,描述一条路.

输出
一个整数,满足题目要求的最佳牧场.如果有多个答案,输出编号最小的

分析

本人用floyd算法写的。
①处理输入先将road数组赋值成较大值,在最后C行输入时再将某些数据进行赋值。代码如下:

scanf("%d%d%d",&n,&p,&m);
F(i,1,p)scanf("%d",&a[i]);
memset(road,62,sizeof(road));
F(i,1,n)road[i][i]=0;
F(i,1,m)scanf("%d%d%d",&x,&y,&k),road[x][y]=road[y][x]=min(road[x][y], k);

②用floyd无脑枚举多源最短路径。如:

F(k,1,n)F(i,1,n)F(j,1,n)road[i][j]=min(road[i][j],road[i][k]+road[k][j]);

③在计算每个点到a[i](即为某头牛喜欢的牧场)的距离,求最优质即可。如:

F(i,1,n){
sum=0;
F(j,1,p)sum+=road[i][a[j]];
if(sum<bet)bet=sum,ans=i;
}

完整代码如下:

#include<bits/stdc++.h>
#define F(a,b,c)for(int a=b;a<=c;a++)
using namespace std;
int road[505][505],a[505],n,m,p,i,x,y,j,k,ans,bet,sum;
int main(){
	scanf("%d%d%d",&n,&p,&m);
	F(i,1,p)scanf("%d",&a[i]);
	memset(road,62,sizeof(road));
	F(i,1,n)road[i][i]=0;
	F(i,1,m)scanf("%d%d%d",&x,&y,&k),road[x][y]=road[y][x]=min(road[x][y], k);
	F(k,1,n)F(i,1,n)F(j,1,n)road[i][j]=min(road[i][j],road[i][k]+road[k][j]);
	bet=INT_MAX;
	F(i,1,n){
		sum=0;
		F(j,1,p)sum+=road[i][a[j]];
		if(sum<bet)bet=sum,ans=i;
	}
	printf("%d\n",ans);
	return 0;
}

②Zju1082 谣言的传播

描述
China历史最伟大的SPY金无怠潜入了美国的FBI,为了整掉这个罪恶的机构,他决定在FBI散布假消息。他首先选定FBI中的某一个职员,将谣言告诉他,然后这个人会将消息再告诉给每一个他认识的人,当然在这个过程中需要花费一定的时候。然后这些人又会把消息告诉给每一个他所认识的人。这样消息就可能传遍整个FBI,当然每个人知道这个消息的时间有先有后。我们希望最晚才知道这个消息的人他所需要的时间越短越好(设这个时间长度为T)。那么金无怠应该选择哪一个人做为消息的首发者呢?请输出这个人的编号及T。如果消息不能传遍FBI请输出"disjoint"
注意从职员A传播谣言给职员B的时间不一定等于从职员B传播谣言给职员A的时间。

输入
先给出FBI中有多少个职员,用数字N(N<=100)来代表。
接下来N行,用来描述这N个职员。
每一行给出这个职员他认识几个人,然后给出所认识的职员的编号及传消息给他所要花的时间.

,注意两点间可能会有多条路径
输出
如题

样例
输入
3
2 2 4 3 5
2 1 2 3 6
2 1 2 2 2
输出
3 2

分析

此题用floyd算法实现,与某题相似,此处不做详细讲解

完整代码如下

#include<bits/stdc++.h>
#define F(a,b,c)for(int a=b;a<=c;a++)
using namespace std;
int v[505][505],a[505],n,m,p,i,x,y,j,k,ans,bet,c;
int main(){
	cin>>n;
	memset(v,62,sizeof(v));
	F(i,1,n)v[i][i]=0;
	F(i,1,n){
		cin>>m;
		F(j,1,m)cin>>x>>y,v[i][x]=min(v[i][x],y);
	}
	F(k,1,n)F(i,1,n)F(j,1,n)v[i][j]=min(v[i][j],v[i][k]+v[k][j]);
	bet=INT_MAX;
	F(i,1,n){
		c=0;
		F(j,1,n)c=max(c,v[i][j]);
		if(c<bet)bet=c,ans=i;
	}
	if(bet==INT_MAX)cout<<"disjoint";
	printf("%d %d",ans,bet);
	return 0;
}

③Cow Hurdles 奶牛跨栏

Description
Farmer John 想让她的奶牛准备郡级跳跃比赛,贝茜和她的伙伴们正在练习跨栏。她们很累,所以她们想消耗最少 的能量来跨栏。 显然,对于一头奶牛跳过几个矮栏是很容易的,但是高栏却很难。于是,奶牛们总是关心路径上 最高的栏的高度。 奶牛的训练场中有 N (1 ≤ N ≤ 300) 个站台,分别标记为1…N。所有站台之间有M (1 ≤ M ≤ 25,000)条单向路径,第i条路经是从站台Si开始,到站台Ei,其中最高的栏的高度为Hi (1 ≤ Hi ≤ 1,000,00 0)。无论如何跑,奶牛们都要跨栏。 奶牛们有 T (1 ≤ T ≤ 40,000) 个训练任务要完成。第 i 个任务包含两个 数字 Ai 和 Bi (1 ≤ Ai ≤ N; 1 ≤ Bi ≤ N),表示奶牛必须从站台Ai跑到站台Bi,可以路过别的站台。奶牛们 想找一条路径从站台Ai到站台Bi,使路径上最高的栏的高度最小。 你的任务就是写一个程序,计算出路径上最高 的栏的高度的最小值。

Input
行 1: 两个整数 N, M, T 行
2…M+1: 行 i+1 包含三个整数 Si , Ei , Hi 行 M+2…M+T+1: 行 i+M+1 包含两个整数,表示任务i的起始站台和目标站台: Ai , Bi

Output
行 1…T: 行 i 为一个整数,表示任务i路径上最高的栏的高度的最小值。如果无法到达,输出 -1。

Sample input
5 6 3
1 2 12
3 2 8
1 3 5
2 5 3
3 4 4
2 4 8
3 4
1 2
5 1
Sample output
4
8
-1

分析

此题可依旧使用floyd算法,求的是路径上最大值的最小值。
①输入处理。先将D数组赋成超大值,再把D[Si][Ei]赋成Hi。如:

scanf("%d%d%d",&n,&m,&t);
memset(D,127,sizeof(D));
F(i,1,m)scanf("%d%d%d",&a,&b,&h),D[a][b]=h;

②再套用floyd模板,此处要稍做处理。
先求出i到中转点k,k到j路上的最大值,再与i到j路上的最大值进行比较,取最小值即可。如:

F(k,1,n)F(i,1,n)F(j,1,n)if(i!=j&&j!=k&&i!=k)D[i][j]=min(max(D[i][k],D[k][j]),D[i][j]);

③最后输出D[Ai][Bi]的值即可。若仍为超大值,输出-1.如:

for(int i=1;i<=t;i++){
	scanf("%d%d",&S,&E);
	D[S][E]<2139062143?printf("%d\n",D[S][E]):printf("-1\n");
	//2139062134为超大值
}

最后附上完整代码

#include <bits/stdc++.h>
#define F(a,b,c)for(int a=b;a<=c;a++)
using namespace std;
int n,m,t,a,b,h,D[301][301],S,E;
int main(){
	scanf("%d%d%d",&n,&m,&t);
	memset(D,127,sizeof(D));
	F(i,1,m)scanf("%d%d%d",&a,&b,&h),D[a][b]=h;
	F(k,1,n)F(i,1,n)F(j,1,n)
		if(i!=j&&j!=k&&i!=k)
			D[i][j]=min(max(D[i][k],D[k][j]),D[i][j]);
	for(int i=1;i<=t;i++){
		scanf("%d%d",&S,&E);
		D[S][E]<2139062143?printf("%d\n",D[S][E]):printf("-1\n");
	}
	return 0;
}

floyd代码比较清爽,此题floyd不会超时。
Floyd为n³算法,因此谨慎使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值