【数据结构图】floyed最短路径-牛的旅行

**

【问题描述】

**
农民John的农场里有很多牧区。有的路径连接一些特定的牧区。一片所有连通的牧区称为一个牧场。但是就目前而言,你能看到至少有两个牧区不连通。现在,John想在农场里添加一条路径 ( 注意,恰好一条 )。对这条路径有这样的限制:一个牧场的直径就是牧场中最远的两个牧区的距离 ( 本题中所提到的所有距离指的都是最短的距离 )。考虑如下的两个牧场,图1是有5个牧区的牧场,牧区用“*”表示,路径用直线表示。每一个牧区都有自己的坐标:

图1所示的牧场的直径大约是12.07106, 最远的两个牧区是A和E,它们之间的最短路径是A-B-E。   这两个牧场都在John的农场上。John将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。注意,如果两条路径中途相交,我们不认为它们是连通的。只有两条路径在同一个牧区相交,我们才认为它们是连通的。   现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。
【输入格式】
  第 1 行:一个整数N (1 <= N <= 150), 表示牧区数;   第 2 到 N+1 行:每行两个整数X,Y ( 0 <= X,Y<= 100000 ), 表示N个牧区的坐标。每个牧区的坐标都是不一样的。   第 N+2 行到第 2*N+1 行:每行包括N个数字 ( 0或1 ) 表示一个对称邻接矩阵。   例如,题目描述中的两个牧场的矩阵描述如下:       A B C D E F G H      
A 0 1 0 0 0 0 0 0      
B 1 0 1 1 1 0 0 0      
C 0 1 0 0 1 0 0 0      
D 0 1 0 0 1 0 0 0      
E 0 1 1 1 0 0 0 0      
F 0 0 0 0 0 0 1 0      
G 0 0 0 0 0 1 0 1      
H 0 0 0 0 0 0 1 0   
输入数据中至少包括两个不连通的牧区。

【输出格式】

只有一行,包括一个实数,表示所求答案。数字保留六位小数。

【输入样例】

8
  10 10
  15 10
  20 10
  15 15
  20 15
  30 15
  25 10
  30 10
  01000000
  10111000
  01001000
  01001000
  01110000
  00000010
  00000101
  00000010
【输出样例】
22.071068

下边是自己的理解笔记

**

#include<bits/stdc++.h>
using namespace std;

double f[151][151],x[151],y[151],m[151];
double minx,tmp,maxint=1e12;
double dis(int i,int j){
	return sqrt(pow(double(x[i]-x[j]),2)+pow(double(y[i]-y[j]),2));
	//求两个坐标点之间的距离,数学公式 
}
int main(){
	freopen("x.in","r",stdin); 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
	char c;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		cin>>c;
		if(c=='1') f[i][j]=dis(i,j);//如果是1表示有一条边,就计算两点之前的距离 
		else f[i][j]=maxint;//不连通就赋值一个很大的数 
	}
	
	for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		if(i!=j &&j!=k && i!=k)
		    //if((f[i][k]<maxint-1)&&(f[k][j]<maxint-1))
		        if(f[i][j]>f[i][k]+f[k][j])
		        f[i][j]=f[i][k]+f[k][j];
	}
	//floyed算法,求i到j的最短路径,中间点k在第一层循环中, 
	//然后i到k和j到k得是连通的,有必要吗?不进行if判断的话,如果不连通f[i][k]值应该是很大的,和不可能比f[i][j]小 
	
	memset(m,0,sizeof(m));
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		if((f[i][j]<maxint-1)&&(m[i]<f[i][j])) m[i]=f[i][j];
	}
	//如果i和j是连通的,m[i]找的是跟i连通的所有路径中最大的值 ,但是还并不是牧场半径 
	 
	
	minx=1e20;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		if(i!=j && f[i][j]>maxint-1)//i和j当前要是不连通的话, 
		{
			tmp=dis(i,j);
			//求出来i到j的距离,那么连接这两个点之后,最新的牧场半径就应该是 
			//i到所有点的最大路径和j到所有点的最大路径再加上i到j的距离
			//也就是m[i]+m[j]+tmp
			//我们需要考虑的是连接那两个点能够使牧场半径最小,所以取的是所有可能中的最小值
		
			if(minx>m[i]+m[j]+tmp) minx=m[i]+m[j]+tmp;
		}
	}
	//当然求出来的最小值也不就是最终的牧场半径,新的连通图可能缩短了牧场半径,但是也有可能没缩短,
	//最后还要在取max(minx,m[i]) 
	for(int i=1;i<=n;i++)
	    if(minx<m[i]) minx=m[i];
	
	printf("%.6lf",minx);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值