洛谷 P1522 牛的旅行 Cow Tours

题目链接:https://www.luogu.org/problem/P1522

思路:编号,然后跑floyd,这是很清楚的。然后记录每个点在这个联通块中的最远距离。

然后分连通块,枚举两个点(不属于同一个连通块的)建边,计算可能的直径 dist[i] + dist[j] + dis(i,j)。

当然,这里有一个需要注意,(sccno[x]表示属于哪一个编号的连通块,sccdis[x]表示该连通块的直径),

在枚举点建边,形成新的牧场,得到新的可能的直径时,dist[i] + dist[j] + dis(i,j) >= max(sccdis[sccno[i]],sccdis[sccno[j]]),

这个是一定要成立的,因为新的可能的直径不可能小于sccdis[sccno[i]] 和 sccdis[sccno[j]](结合题目意思)。


  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <map>
  7 #include <cmath>
  8 using namespace std;
  9 
 10 typedef long long LL;
 11 #define inf 1e11
 12 #define rep(i, j, k) for (int i = (j); i <= (k); i++)
 13 #define rep__(i, j, k) for (int i = (j); i < (k); i++)
 14 #define per(i, j, k) for (int i = (j); i >= (k); i--)
 15 #define per__(i, j, k) for (int i = (j); i > (k); i--)
 16 
 17 const int N = 160;
 18 int G[N][N];
 19 double f[N][N];
 20 double dist[N];
 21 int sccno[N];
 22 int scccnt;
 23 double sccdis[N];
 24 int scct;
 25 int head[N];
 26 int cnt;
 27 int n;
 28 
 29 struct node{
 30     double x,y;
 31 }po[N];
 32 
 33 struct Edge{
 34     int to;
 35     double w;
 36     int next;
 37 }e[N*N];
 38 
 39 void add(int u,int v,double w){
 40     e[cnt].to = v;
 41     e[cnt].w = w;
 42     e[cnt].next = head[u];
 43     head[u] = cnt++;
 44 }
 45 
 46 inline double dis(node& a,node& b){
 47     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 48 }
 49 
 50 void dfs(int u){
 51     sccno[u] = scccnt;
 52     for(int o = head[u]; ~o; o = e[o].next){
 53         int v = e[o].to;
 54         if(!sccno[v]) dfs(v);
 55     }
 56 }
 57 
 58 int main(){
 59 
 60     scanf("%d",&n);
 61 
 62     //链式前向星
 63     rep(i,1,n) head[i] = -1;
 64     cnt = 0;
 65     
 66     //距离矩阵初始化
 67     rep(i,1,n) rep(j,1,n){
 68         if(i == j) f[i][j] = 0;
 69         else f[i][j] = inf;
 70     }
 71 
 72     //点的输入
 73     rep(i,1,n){
 74         scanf("%lf%lf",&po[i].x,&po[i].y);
 75     }
 76 
 77     //读图
 78     rep(i,1,n){
 79         rep(j,1,n) scanf("%1d",&G[i][j]);
 80     }
 81     
 82     //建边
 83     double way;
 84     rep(i,1,n) rep(j,i+1,n){
 85         if(G[i][j]){
 86             way = dis(po[i],po[j]);
 87             f[j][i] = f[i][j] = way;
 88             add(i,j,way);
 89             add(j,i,way);
 90         }      
 91     }
 92 
 93     //连通图
 94     rep(i,1,n) if(!sccno[i]){
 95         ++scccnt;
 96         dfs(i);
 97     }
 98 
 99 
100     //最短路
101     rep(k,1,n) rep(i,1,n) rep(j,1,n){
102        f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
103     }
104 
105     rep(i,1,n){
106         rep(j,1,n){
107             if(f[i][j] == inf) continue;
108             dist[i] = max(dist[i],f[i][j]);
109         }
110     }
111 
112     //连通块最长直径
113     rep(i,1,n){
114         sccdis[sccno[i]] = max(sccdis[sccno[i]],dist[i]);
115     }
116 
117     double ans_1 = inf;
118     double tmp;
119     rep(i,1,n) rep(j,1,n){
120         if(f[i][j] == inf){
121             tmp = max(sccdis[sccno[i]],sccdis[sccno[j]]);
122             ans_1 = min(ans_1,dist[i] + dist[j] + dis(po[i],po[j]));
123             ans_1 = max(ans_1,tmp);
124         }
125     }
126 
127     printf("%.6f\n",ans_1);
128 
129     getchar();getchar();
130     return 0;
131 }

 

posted @ 2019-09-05 16:30  SummerMingQAQ  阅读(217)  评论(0编辑  收藏  举报