问题 C: 例4-2牛的旅行

Posted Icy Hunter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了问题 C: 例4-2牛的旅行相关的知识,希望对你有一定的参考价值。

问题 C: 【例4-2】牛的旅行

输入
第 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

这题先用Floyd计算出任意两点的最短路径,如果不连通那么路径就是inf,然后遍历各个点寻找每个点距离自己牧场最远的那个点的距离储存在mindis中,其中就包含着牧场的最大半径,然后再遍历,寻找不连通的点连通之后这条路的距离(即mindis[i]+mindis[j]+f(x[i],y[i],x[j],y[j]))的最小值(因为有可能成为新的牧场的最大半径的情况),然后记录下来,再去和两个牧场原本的半径相比较(最简单就是遍历mindis数组),如果原本的半径就大于连接之后形成的新的半径,那么肯定是要取原来的才符合条件。

#include<bits/stdc++.h>
using namespace std;
double G[151][151];
double x[151],y[151];
int n;
char s[151];
#define inf 88888888
double mindis[151];

double f(double a,double b,double xx,double yy)
{
	return sqrt(pow((a-xx),2)+pow((b-yy),2));//求出距离 
}

void floyd()
{
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(G[i][j]>G[i][k]+G[k][j]&&k!=i&&k!=j&&i!=j) 
				G[i][j]=G[i][k]+G[k][j]; 
				//遍历求出任意两个点的最短路径(i经过k到j如果比i直接到j要近,那么就更新最短路径)
			}
		}
	}
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%lf %lf",&x[i],&y[i]);//输入坐标x,y 
	}
	
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s);
        int l = strlen(s);
        for(int j=0;j<l;j++)
		{

			if(s[j]=='0')G[i][j+1]=inf;//如果遇到0即不通就赋值inf否则就调用f()计算距离 
			else 
			{
			  G[i][j+1]=f(x[i],y[i],x[j+1],y[j+1]);//j从0开始所以+1以匹配i 
			}
		}
	}
	
	floyd();//计算所有两点之间的最短路径 
	
	memset(mindis,0,sizeof(mindis));
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(mindis[i]<G[i][j]&&G[i][j]<inf&&i!=j)mindis[i]=G[i][j];
			//mindis[i]存储另外的点到i这个点的最大距离,其中的某几个mindis[i]其实就是牧场的最大半径 
		}
	}
	
	double minn = inf;
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(G[i][j]==inf&&i!=j&&mindis[i]+mindis[j]+f(x[i],y[i],x[j],y[j])<minn)
			//G[i][j]==inf表明这两点不通,即为两个不同的牧场的点,不会重合
			//然后连接这两个点的长度加上各自到自己牧场的最大距离,即为最终的牧场的半径 
			minn=mindis[i]+mindis[j]+f(x[i],y[i],x[j],y[j]);
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		if(mindis[i]>minn)minn=mindis[i];//如果原本牧场的最大半径就大于连接后的牧场的最大半径,那就取原本的那个才符合条件。 
	}
	printf("%.6lf",minn);
	return 0;
}

以上是关于问题 C: 例4-2牛的旅行的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1522牛的旅行——floyd

codevs 1405 牛的旅行x

AcWing1125 牛的旅行(floyd)

luogu1522 牛的旅行

P1522 牛的旅行 (Floyed)

1125. 牛的旅行floyd算法