【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())=='\n'||point==' '||point=='\r'); 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 }
当然,如果牧场不是两个,就相对麻烦一点,可以去参考dalao的题解:https://minamoto.blog.luogu.org/solution-p1522