牛的旅行 Cow Tours——floyd+连通块

P1522 [USACO2.4] 牛的旅行 Cow Tours - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

一、题意分析

  1. 牧区: 对应一个点。
  2. 牧区之间的距离:实际上是两点之间的 最短路。 不要理解成欧几里得距离。只有 直接连接 的时候,才可以计算欧几里得距离。
  3. 牧场: 一个连通块。
  4. 牧场直径: 一个牧场的直径是这个牧场所有的牧区(点)之间 距离 的最大值。 说的绕一点就是 最短路的最大值。
  5. 使用一条边连接两个牧场,使得合成的一个新的牧场的直径最小。意思是加入一条边之后,使得新的牧场的所有点对之间 最短路 的最大值 最小

 

二、解法

  1. 使用 DFS 对连通块染色标记:区分牧场。O(V + E) = O(n^2)O(V+E)=O(n2)
  2. 使用 Floyd-Warshall 算法计算所有点对之间的 最短路。 O(n^3)O(n3)
  3. 计算每个牧场中,每个牧区点到其他点的 最短路 的最大值。(后面加边的时候要用)
  4. 计算每个牧场中,所有最短路的最大值,即每个牧场的直径。 这个可以与 3 一起计算。 O(n^2)O(n2)
  5. 最后是找答案:对任意两个点,先判断是否同一个牧场。如果不是,考虑加入一条边,变成一个新的牧场。可以直接计算出通过这条边的最短路的最大值。 需要注意的是,通过这条边的最短路的最大值不一定是新牧场的所有最短路的最大值。这里需要比较三个值(牧场 A 的所有最短路的最大值; 牧场 B 的所有最短路的最大值, 加边后通过这条边的最短路的最大值),才能得到正确的新牧场的直径。 遍历所有点对(或者一半), 找出 “新直径” 的最小值。 O(n^2)O(n2)

最后的时间复杂度是 O(n^3)O(n3)。 空间复杂度也只是 O(n^2)O(n2)。

 

太恶心了,没注意到double类型数组memset不能用0x3f,啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊气死我了气死我了气死我了,卡了一个小时,气死我了气死我了!!!!!!!!!!!!!!!!!!!!

 

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 inline int read()
  4 {
  5     int sum=0;char a=getchar();
  6     while(a<'0'||a>'9')a=getchar();
  7     while(a>='0'&&a<='9')
  8     {
  9         sum=(sum<<3)+(sum<<1)+a-'0';
 10         a=getchar();
 11     }
 12     return sum;
 13 }
 14 
 15 const int N=160;
 16 const double INF=1e20;
 17 int n,field[N];
 18 double dist[N][N],zhijing[N],maxspace[N];
 19 
 20 struct node
 21 {
 22     int x,y;
 23     double distance(const node &b)
 24     {
 25         return sqrt((x - b.x) * (x - b.x) + (y - b.y) * (y - b.y));
 26     }
 27 }a[N];
 28 
 29 void dfs(int i,int id)
 30 {
 31     field[i]=id;
 32     for(int j=0;j<n;j++)
 33     {
 34         if(!field[j]&&dist[i][j]<INF)dfs(j,id);
 35     }
 36 }
 37 
 38 void floyd()
 39 {
 40     for(int k=0;k<n;k++)
 41     {
 42         for(int i=0;i<n;i++)
 43         {
 44             for(int j=0;j<n;j++)
 45                 dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
 46         }
 47     }
 48 }
 49 
 50 
 51 int main()
 52 {
 53     n=read();
 54     for(int i=0;i<n;i++)
 55         a[i].x=read();a[i].y=read(); 
 56     
 57     for(int i=0;i<n;i++)
 58     {
 59         printf("%d %d\n",a[i].x,a[i].y);
 60     }
 61     
 62     char b[N];
 63     for(int i=0;i<n;i++)
 64     {
 65         scanf("%s",b);
 66         for(int j=0;j<n;j++)
 67         {
 68             if(i==j)dist[i][j]=0;
 69             else if(b[j]=='1')dist[i][j]=a[i].distance(a[j]);
 70             else dist[i][j]=INF;
 71         }
 72         
 73     }
 74     
 75     int id=0;        //bfs求连通块 
 76     for(int i=0;i<n;i++)
 77     {
 78         if(!field[i])dfs(i,++id);
 79     }
 80     
 81     floyd();    //floyd求任意两点之间的最短距离 
 82     
 83     for (int i = 0; i < n; ++i)    //求每个连通块内部的直径 
 84     {
 85         maxspace[i] = 0.0;
 86         for (int j = 0; j < n; ++j)
 87             if (dist[i][j] < INF)
 88                 maxspace[i] = max(maxspace[i], dist[i][j]);
 89         zhijing[field[i]] = max(zhijing[field[i]], maxspace[i]);
 90     }
 91     
 92     double min_d = INF, max_d;
 93     for(int i=0;i<n;i++)        //求最后答案 
 94     {
 95         for(int j=i+1;j<n;j++)
 96         {
 97             if(field[i]!=field[j])
 98             {
 99                 max_d = max(max(zhijing[field[i]], zhijing[field[j]]),
100                             maxspace[i] + a[i].distance(a[j]) + maxspace[j]);
101                 min_d = min(min_d, max_d);
102             }
103         }
104     }
105     
106     printf("%.6lf\n",min_d);
107     return 0;
108 }
View Code

 

posted @ 2022-03-05 18:10  wellerency  阅读(40)  评论(0编辑  收藏  举报