【USACO习题】牛的旅行

这道题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1522


真心很无语,怎么会有这么奇怪的题。。。呃呃,题解。大家的做法几乎是一样的,我都不能理解,只有一个人的做法和我想的一样,可是很麻烦。

大家基本都是用Floyd求出每个点所能到达的最远的最短路,设为md[i],枚举不连通的两个结点i和j,求出最小的md[i]+md[j]+dis[i][j](dis[i][j]指两点间距离)。这还不算什么,更坑的是,又求出最大的md[i],将其与min(md[i]+md[j]+dis[i][j])比较,较大的为答案,说是什么将两个牧场连通后,直径如果要经过新路,可能还比原来牧场的直径小,这个很好理解,可是为什么要和所有牧场的直径比较?不应该是求max(dd[i],dd[j],md[i]+md[j]+dis[i][j])吗(dd[i]是指i所在连通块的直径)?然后最小的那个就是答案。

好吧,其实我一直没读懂题。

题目里面说的,刚好有两个牧场(论分不清举例与题目要求的后果)。

这样的话,第一种相对简单的方法就对了。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=155;
 7 const double inf=1e12;
 8 int n,x[maxn],y[maxn];
 9 double md[maxn],G[maxn][maxn],ans=inf;
10 double dis(int i,int j) {
11     return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
12 }
13 int main() { //细节居多,用心体会,没啥好解释的
14     scanf("%d",&n);
15     for(int i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]);
16     for(int i=1;i<=n;++i)
17         for(int j=1;j<=n;++j) G[i][j]=i==j?0:inf;
18     char point;
19     for(int i=1;i<=n;++i) {
20         while((point=getchar())=='
'||point==' '||point=='
');
21         if(point=='1') G[i][1]=dis(i,1);
22         for(int j=2;j<=n;++j) if((point=getchar())=='1') G[i][j]=dis(i,j);
23     }
24     for(int k=1;k<=n;++k)
25         for(int i=1;i<=n;++i)
26             for(int j=1;j<=n;++j)
27                 G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
28     for(int i=1;i<=n;++i)
29         for(int j=1;j<=n;++j) if(G[i][j]!=inf) md[i]=max(md[i],G[i][j]);
30     for(int i=1;i<=n;++i)
31         for(int j=1;j<=n;++j) if(G[i][j]==inf) ans=min(ans,md[i]+md[j]+dis(i,j));
32     for(int i=1;i<=n;++i) ans=max(ans,md[i]);
33     printf("%.6f",ans);
34     return 0;
35 }
AC代码

当然,如果牧场不是两个,就相对麻烦一点,可以去参考dalao的题解:https://minamoto.blog.luogu.org/solution-p1522

原文地址:https://www.cnblogs.com/Mr94Kevin/p/9572007.html