zoukankan      html  css  js  c++  java
  • CF266D BerDonalds(图的绝对中心)

    图的绝对中心在某节点或边上,使得所有节点到此点的距离最大值最小。

    如果绝对中心在点上,那么直接对于每个 (u) 处理出 (dis_{u,x}) 最大的 (x) 即可。

    考虑在边上的情况,若在边 ((u,v,w)) 上距离 (u) 长度为 (x),则节点 (i) 到此点距离为 (min(dis_{u,i}+x,dis_{v,i}+(w-x)))
    把这个东西关于 (x) 的图像画出来就是一个单峰的折线。
    (n) 个点的所有折线都画出来就是这样(来自 oi-wiki):

    实线是 (n) 个点的折线取完 (max) 的图像,然后发现所有实线的极小值的横坐标是可能的 (x) 的取值。
    由于斜率一定,可以按照 (dis_{u,i}) 从大到小考虑。
    (p) 是目前考虑过的所有 (i) 中使得 (dis_{v,i}) 最大的那个,此时 (p) 的那条折线的递减部分一定是完全暴露在外的。
    因此若此时有 (dis_{v,i}>dis_{v,p}),则会在 (p) 的递减部分产生一个新的合法最小值拐点。
    那么此时 (dis_{u,i}+x)(dis_{v,p}+(w-x)) 一定同时是最长路径(还没考虑到的点的拐点在 (i) 的后面,而交点是在 (i) 的拐点前面,因此图像都在 (i) 下面),由此计算更新答案。

    #define N 206
    #define M 40006
    int n,m;
    int val[N];
    int dis[N][N],rank[N][N];
    int u[M],v[M],w[M];
    int main(){
    	n=read();m=read();
    	std::memset(dis,0x3f,sizeof dis);
    	for(reg int i=1;i<=n;i++) dis[i][i]=0;
    	for(reg int u,v,i=1;i<=m;i++){
    		u=::u[i]=read();v=::v[i]=read();
    		dis[u][v]=dis[v][u]=std::min(dis[u][v],w[i]=read());
    	}
    	for(reg int k=1;k<=n;k++){
    		for(reg int i=1;i<=n;i++)for(reg int j=1;j<=n;j++) dis[i][j]=std::min(dis[i][j],dis[i][k]+dis[k][j]);
    	}
    	for(reg int i=1;i<=n;i++){
    		for(reg int j=1;j<=n;j++) val[j]=dis[i][j],rank[i][j]=j;
    		std::sort(rank[i]+1,rank[i]+1+n,[](const int &a,const int &b){return val[a]<val[b];});
    	}
    	int ans=1e9;
    	for(reg int i=1;i<=n;i++) ans=std::min(ans,dis[i][rank[i][n]]<<1);
    	for(reg int i=1;i<=m;i++){
    		int u=::u[i],v=::v[i],w=::w[i];
    		for(reg int j=n-1,p=n;j;j--)if(dis[v][rank[u][j]]>dis[v][rank[u][p]]){
    			ans=std::min(ans,dis[u][rank[u][j]]+dis[v][rank[u][p]]+w);
    			p=j;
    		}
    	}
    	printf("%lf
    ",ans/2.0);
    	return 0;
    }
    
  • 相关阅读:
    题目3:爬楼梯
    题目1:删除排序数组中的重复数字
    最近目标
    软件工程----个人总结
    软件工程第二次作业——结对编程
    软件工程第一次作业补充
    爬楼梯
    买卖股票的最佳时机
    删除排序数组中的重复数字
    思考题
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/15253132.html
Copyright © 2011-2022 走看看