P1522 [USACO2.4]牛的旅行 Cow Tours

博客介绍了P1522题目的解题思路,将牧区抽象为图的节点,牧场视为连通块,并通过最大直径计算确保满足题设条件。使用邻接矩阵存储图,Floyd算法求连通块内最短路径,枚举两点以找到添加边后的最大距离。

P1522 [USACO2.4]牛的旅行 Cow Tours

思路

  • 牧区可以抽象成图上每一个点
  • 牧场可以看作连通块
  • 新牧场的最大直径=两点到未连通前两个牧场的最大距离(保证满足题意:一个牧场的直径就是牧场中最远的两个牧区的最短距离)+两点之间最短距离

实现

  • 邻接矩阵存图
  • floyed计算连通块内最短距离
  • 一个数组存储它所在的连通块的最大距离
  • 枚举任意两点,记录添加后最大距离

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>

using namespace std;

int n;
const int inf=0x3f3f3f3f;
const int maxn=200;
double mp[maxn][maxn];
int k=0;
int f[maxn];
double disf[maxn];
struct nodep{
	int x,y;
}p[maxn];
double ans;
double ll=0;
double disd(int x,int y){
	return sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x)+(p[x].y-p[y].y)*(p[x].y-p[y].y));
} 
int main(){
	scanf("%d",&n);
	memset(disf,0,sizeof(disf)); 
	memset(mp,0,sizeof(mp));
	for(int i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y);
	char c[maxn]; 
	for(int i=1;i<=n;++i){
		scanf("%s",c);
		int len=strlen(c);
		for(int j=1;j<=len;++j){
			if(c[j-1]=='1') mp[i][j]=disd(i,j); 
			else if(i!=j) mp[i][j]=inf*1.0;
		}
	}
	
	//floyed
	for(int kk=1;kk<=n;++kk)
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				mp[i][j]=min(mp[i][j],mp[i][kk]+mp[kk][j]);
				
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			//因为把图上的最短路已经算出,所以 每个点所能到达的最大值 即最远两个点的图上的最短距离
			if(mp[i][j]!=inf) disf[i]=max(disf[i],mp[i][j]);//求每个点能连通的最大距离
 
			ll=max(ll,disf[i]);//未添加路径前的最大直径 
		}
	double lll=inf;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(mp[i][j]==inf)//枚举每一种添加边的情况,取最小值 
				lll=min(disf[i]+disd(i,j)+disf[j],lll);//未连通的两个点添加图上的一条边最短距离+这两点分别到本图上的最短距离即为新图的直径
			
	ans=max(ll,lll);
	printf("%.6f",ans);
	
	return 0; 
}

此题需要理清楚概念(比较绕

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值