寒假做题记录
1.20 Tue
LG P1522
牧场:联通的牧区;牧场的直径:任意两个牧区的距离(最短路)的最大值;目的是连接两个牧场,使得新的大牧场的直径最小,输出的新的直径
1.肯定先求连通块
2.\(N\leq 150\) 且要求任意两个点之间的最短路,所以用 floyd
3.考虑一个新连通块(原来有 \(A,B\) 两个牧场,连了一条 \(i\rightarrow j,\ i\in A, j\in B\) 的边)直径的情况:
①.原来 \(A\) 牧场的直径
②.原来 \(B\) 牧场的直径
③. \(i\rightarrow j\) 的边权 + \(i\) 在 \(A\) 连通块里能达到最远的距离 + \(j\) 在 \(B\) 连通块里能达到的最远距离
4.需要处理的东西:每个连通块内的直径,对于一个连通块内的一个点能达到的最远距离
namespace Solution{
int n;
PII a[maxn];
int p[maxn];
double dis[maxn][maxn], maxdis[maxn], maxblock[maxn];
void init(){
For (i, 1, n) p[i] = i;
}
int find(int x){
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
void combine(int x, int y){
int r1 = find(x), r2 = find(y);
if (r1 == r2) return;
p[r1] = r2;
}
double getdis(double xx1, double yy1, double xx2, double yy2){
return sqrt((xx1 - xx2) * (xx1 - xx2) + (yy1 - yy2) * (yy1 - yy2));
}
void Main(){
cin >> n;
init();
For (i, 1, n) cin >> a[i].fi >> a[i].se;
For (i, 1, n){
string s; cin >> s;
For (j, 0, sz(s) - 1){
int jj = j + 1;
if (s[j] == '1'){
combine(i, jj);
dis[i][jj] = getdis(a[i].fi, a[i].se, a[jj].fi, a[jj].se);
} else if (s[j] == '0' && i == jj){
dis[i][jj] = 0;
} else{
dis[i][jj] = inf;
}
}
}
For (k, 1, n){
For (i, 1, n){
For (j, 1, n){
upmin(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
For (i, 1, n){
For (j, 1, n){
if (find(i) == find(j)){
upmax(maxdis[i], dis[i][j]);
}
upmax(maxblock[find(i)], maxdis[i]);
}
}
double ans = (double)inf;
For (i, 1, n){
For (j, 1, n){
int r1 = find(i), r2 = find(j);
if (r1 == r2) continue;
double k1 = maxblock[r1];
double k2 = maxblock[r2];
double k3 = maxdis[i] + maxdis[j] + getdis(a[i].fi, a[i].se, a[j].fi, a[j].se);
ans = min(ans, max(k1, max(k2, k3)));
}
}
cout << fixed << setprecision(6) << ans << endl;
}
};

浙公网安备 33010602011771号