P1522 [USACO2.4]牛的旅行 Cow Tours

题意

直径:一个牧场(连通块)中任意两点最短路的最大值。

给你一张无向带权图,图中有一些连通块,试连接图中两个不同的连通块中的一点,是新的连通块直径最小。

分析

  • 我们需要把图存下来,于是用 wi,j=(xixj)2+(yiyj)2w_{i,j}=\sqrt{(x_i-x_j)^2+(y_i-y_j)^2} 代表边权。

  • 我们需要找出图中的连通块,于是 dfs\text{dfs} 对每个块染色,把每个连通块的点放进对应的 vector c2col\text{vector}\ c2_{col} 里。

  • 我们需要知道任意两点之间的最短路,于是跑了 floyd nnDijkstra\text{Dijkstra} 求最短路 di,jd_{i,j}

  • 我们需要知道每个连通块的直径 czcolcz_{col},于是我们需要知道每个点到块中其他点的最短路的最大值 mxdc2col,imxd_{c2_{col,i}},就可以知道 czcol=max{mxdc2col,i}cz_{col}=\max\{mxd_{c2_{col,i}}\}

  • 我们需要找出答案,于是暴力枚举两个点 i,ji,j,如果 i,ji,j 不在同一个连通块内,那么连接后的新直径可能在两个原来的连通块内,也可能是连接之后形成的,也就是 max(czcoli,czcolj,mxdi+wi,j+mxdj)\max(cz_{col_i},cz_{col_j},mxd_i+w_{i,j}+mxd_j)。答案就是所有情况的最小值。

  • 我们需要知道这样写会不会错,还没等你算出时间复杂度 O(n2logn)O(n^2\log n),你的程序已经在 100ms\text{100ms}AC\text{AC} 了。

代码

#include<bits/stdc++.h>
#define qw first
#define er second
using namespace std;
const int N=200;
int n,c[N];//c[i]是i所在的连通块 
double x[N],y[N],w[N][N],d[N][N],mxd[N],cz[N],mx=1e9;
bool a[N][N],v[N];
vector<int>c2[N];
priority_queue<pair<double,int> >q;
pair<double,int>e;
void dfs(int x,int col){
	if(v[x]) return;
	v[x]=1;c[x]=col;
	c2[col].push_back(x);
	for(int i=1;i<=n;i++)
		if(a[x][i])
			dfs(i,col);
}
void Dijkstra(int s){
	memset(v,0,sizeof(v));
	d[s][s]=e.qw=0;e.er=s;
	q.push(e);
	while(q.size()){
		int x=q.top().er;
		q.pop();
		if(v[x])
			continue;
		v[x]=1;
		for(int i=1;i<=n;i++){
			if(!a[x][i])
				continue;
			if(d[s][i]>d[s][x]+w[x][i]){
				d[s][i]=d[s][x]+w[x][i];
				e.qw=-d[s][i];e.er=i;
				q.push(e);
			}
		}
	}
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    		d[i][j]=1e7;
    for(int i=1;i<=n;i++)
    	cin>>x[i]>>y[i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%1d",&a[i][j]);
			w[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
		}
	}
	for(int i=1;i<=n;i++)
		Dijkstra(i);
	memset(v,0,sizeof(v));
	for(int i=1,col=1;i<=n;i++){
		if(v[i]) continue;
		dfs(i,col);
		for(int j=0;j<c2[col].size();j++){
			for(int k=0;k<c2[col].size();k++){
				if(j==k||d[c2[col][j]][c2[col][k]]==1e7) continue;
				mxd[c2[col][j]]=max(mxd[c2[col][j]],d[c2[col][j]][c2[col][k]]);
			}
			cz[col]=max(cz[col],mxd[c2[col][j]]);
		}
		col++;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(c[i]==c[j]) continue;
			mx=min(mx,max(cz[c[i]],max(cz[c[j]],mxd[i]+w[i][j]+mxd[j])));
		}
	printf("%.6lf",mx);
	return 0;
}
posted @ 2021-08-19 20:07  luckydrawbox  阅读(9)  评论(0)    收藏  举报  来源