1. 程式人生 > >【USACO習題】牛的旅行

【USACO習題】牛的旅行

理解 alt lap line 原來 連通塊 很好 只有一個 ring

這道題在洛谷上的鏈接: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 }
AC代碼

當然,如果牧場不是兩個,就相對麻煩一點,可以去參考dalao的題解:https://minamoto.blog.luogu.org/solution-p1522

【USACO習題】牛的旅行