题目链接:https://www.luogu.org/problem/P1522
题目大意:
原题在链接里,但是原题读起来比较晕,我在这里转化了一下题意。
给出N个点的坐标,然后给出这N个点的邻接矩阵。
例如:
A B
A 0 1 代表A与B直接连接
B 1 0
给出的邻接矩阵是几个连通图,然后你可以加一条边(只能加一条),使两个连通图变成一个连通图,问你如何加边才能使新得到的连通图中两个点的最大距离最小。
用文字不好解释还是有点绕,上图:
最初有 A B C 三个连通图
原本三个连通图在加了c-----d这条边后变成了两个连通图,求A'中的最长距离L (任意两个点的距离的最大值)
然而对于几个连通图,你有多种选择,即会得到很多的L,依次设为:L1,L2,L3........ 要求其中的最小值
思路:
N <= 150;
涉及到了任意两点的距离,N 又不大,很容易想到floyd,我们先用Floyd跑一遍,求出任意两个点的距离,不连通点的距离为无穷大
dist[i][j] 即为 i 到 j 的 最短距离
然后我们在求出每个点在他所在的连通图中到其他点的距离的最大值,设为maxDist[i]
接下来就是枚举任意两个不连通的点i , j ,则此时在新得到的连通图中的最大距离为:maxDist[i] + maxDist[j] + calDist(i, j) {calDist(i,j)是计算i,j距离的函数}
加了d - e 这条边
但是求出来的距离话=还有可能小于其他连通图中的最大距离,所以最后要进行比较。
详情见代码:
1 /* 2 2019-10-26 3 洛谷-P1522 牛的旅行 Cow Tours 4 *** 5 */ 6 7 #include <cstdio> 8 #include <iostream> 9 #include <cmath> 10 using namespace std; 11 const int N = 200; 12 const int INF = 0x3f3f3f3f; 13 14 int n; 15 double dist[N][N]; //任意两点的距离 16 double maxDist[N]; //在自己所在连通图中到其他的最大距离 17 18 //first是为没有加边之前的最大值,second是加边后的最大值 19 double first = 0, second = INF; 20 21 22 //结构体存点 23 struct POINT 24 { 25 int x, y; 26 }point[N]; 27 28 //计算 a b 之间的距离 29 double calDist(int a, int b) 30 { 31 double x1 = point[a].x, y1 = point[a].y; 32 double x2 = point[b].x, y2 = point[b].y; 33 return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); 34 } 35 36 void solve() 37 { 38 cin >> n; 39 for(int i = 1; i <= n; i++) scanf("%d %d", &point[i].x, &point[i].y); 40 for(int i = 1; i <= n; i++) 41 for(int j = 1; j <= n; j++) 42 { 43 int t; 44 scanf("%1d", &t); 45 //如果相连就直接计算两点的距离 46 if(t == 1) dist[i][j] = dist[j][i] = calDist(i, j); 47 //到自己的距离为0 48 else if(i == j) dist[i][j] = dist[j][i] = 0; 49 //不相连设为无穷大 50 else dist[i][j] = dist[j][i] = INF; 51 } 52 53 //Floyd模板跑一边,跑完后如果两个点的距离为无穷大,说明两个点不在一个连通图 54 for(int k = 1; k <= n; k++) 55 for(int i = 1; i <= n; i++) 56 for(int j = 1; j <= n; j++) 57 dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 58 59 //计算maxDist数组和first 60 for(int i = 1; i <= n; i++) //依次枚举每个点 61 { 62 for(int j = 1; j <= n; j++) //枚举其余点 63 if(dist[i][j] != INF) //如果两个点是连通的 64 maxDist[i] = max(maxDist[i], dist[i][j]); 65 first = max(first, maxDist[i]); 66 } 67 68 //枚举所有情况 69 for(int i = 1; i <= n; i++) 70 for(int j = i+1; j <= n; j++) 71 if(dist[i][j] == INF) //距离为无穷大即不连通,可以加边 72 second = min(second, maxDist[i] + maxDist[j] + calDist(i, j));//取所有情况的最小值 73 double ans = max(first, second); 74 printf("%.6lf\n", ans); 75 } 76 77 int main() 78 { 79 solve(); 80 return 0; 81 }