P1522 [USACO2.4]牛的旅行 Cow Tours
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;
}
此题需要理清楚概念(比较绕