zoukankan      html  css  js  c++  java
  • 题解-bzoj4061 CERC-2012Farm and Factory

    Problem

    Please contact lydsy2012@163.com!

    题意概要:给定(n)(m)边无向图,设定两个起点为(1,2),现要求在图中增加一个点,并将这个点与其他(n)个点每个点连一条边(共(n)条),要求连完边后在新的图中从原来(n)个点到任一起点的最短路不一定经过新点,最小化连的(n)条边的权值和

    Solution

    超好玩的一道题

    (a_i,b_i)分别表示从(1,2)出发到达(i)节点的最短路,设新增节点为(t)(d_i)表示从(t)(i)所连的边

    发现由于最短路不能经过(t),所以

    (d_1+d_igeq a_i\d_2+d_igeq b_i)

    (d_igeq max(a_i-d_1,b_i-d_2))

    假定已经确定了(d_i),希望(d_1)最小,发现若(d_1> a_i+d_i)(d_1=a_i+d_i)是等价的,因为即便(d_1)再大,在考虑后面的点时(a_i+d_i)会代替(d_1)来计算后面的限制,所以有(d_1leq a_i+d_i),同理可得

    (d_1leq a_i+d_i\d_2leq b_i+d_i)

    综上,可得

    (d_igeq max(a_i-d_1,d_1-a_i,b_i-d_2,d_2-b_i)=max(|a_i-d_1|,|b_i-d_2|))

    然后要最小化(sum d_i),假定已经确定(d_1,d_2),则每个(d_i)一定取不等式的等号时最优,即要求最小化的式子为(sum max(|a_i-d_1|,|b_i-d_2|))

    现在只需要确定(d_1,d_2)了。将这个东西放在二维平面上,即有(n)个点((a_i,b_i)),发现上面的式子就是((d_1,d_2))关于(n)个点的切比雪夫距离

    问题转化为确定一个点((d_1,d_2))使得这个点到(n)个点的切比雪夫距离和最小。这是个经典问题,可以将坐标轴旋转(45°)将切比雪夫距离转化为曼哈顿距离

    最小化一个点到(n)个点的曼哈顿距离之和可以将横纵坐标拆开分别取最小,即横坐标取(n)个点横坐标的中位数,纵坐标取(n)个点纵坐标的中位数

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    inline void read(int&x){
    	char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
    	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
    }
    
    const int N=101000,M=301000;
    const ll inf = 0x3f3f3f3f3f3f3f3f;
    struct Edge{int v,nxt,w;}a[M+M];
    ll A[N],B[N];int head[N];
    int n,m,_;
    
    namespace SpFa{
    	int top;
    	struct node{
    		int x;ll v;
    		inline node(){}
    		inline node(const int&X,const ll&V):x(X),v(V){}
    	}h[M];
    	inline void push(node nw){
    		h[++top]=nw;
    		int pp=top;
    		while(pp>1&&h[pp].v<h[pp>>1].v)
    			swap(h[pp],h[pp>>1]),pp>>=1;
    	}
    	inline void pop(){
    		int pp=1;
    		h[1]=h[top--];
    		while(((pp<<1)<=top&&h[pp].v>h[pp<<1].v)||((pp<<1|1)<=top&&h[pp].v>h[pp<<1|1].v)){
    			pp<<=1;
    			if(h[pp].v>h[pp|1].v)pp|=1;
    			swap(h[pp],h[pp>>1]);
    		}
    	}
    
    	void main(int s,ll*dis){
    		for(int i=1;i<=n;++i)dis[i]=inf;
    		h[top=1]=node(s,0ll),dis[s]=0;
    		node nw;
    		while(top){
    			nw=h[1];pop();
    			for(int i=head[nw.x];i;i=a[i].nxt)
    				if(dis[a[i].v]>dis[nw.x]+a[i].w){
    					dis[a[i].v]=dis[nw.x]+a[i].w;
    					push(node(a[i].v,dis[a[i].v]));
    				}
    		}
    	}
    }
    
    void init(){
    	read(n),read(m),_=0;
    	for(int i=n;i;--i)head[i]=0;
    	for(int i=1,u,v,w;i<=m;++i){
    		read(u),read(v),read(w);
    		a[++_].v=v,a[_].w=w,a[_].nxt=head[u],head[u]=_;
    		a[++_].v=u,a[_].w=w,a[_].nxt=head[v],head[v]=_;
    	}
    }
    
    void work(){
    	ll x,y,Ans=0ll;
    	for(int i=n;i;--i)
    		x=A[i],y=B[i],A[i]=x+y,B[i]=x-y;
    	sort(A+1,A+n+1);sort(B+1,B+n+1);
    	x=A[n+1>>1],y=B[n+1>>1];
    	for(int i=n;i;--i)
    		Ans+=abs(A[i]-x)+abs(B[i]-y);
    	printf("%.9lf
    ",0.5*Ans/n);
    }
    
    int main(){
    	int T;read(T);
    	while(T--){
    		init();
    		SpFa::main(1,A);
    		SpFa::main(2,B);
    		work();
    	}return 0;
    }
    
  • 相关阅读:
    C#编程(七十九)---------- 反射
    C#编程(七十一)---------- 自定义特性
    C#编程(七十六)----------使用指针实现基于栈的高性能数组
    C#编程(七十五)----------C#使用指针
    微信开发之移动手机WEB页面(HTML5)Javascript实现一键拨号及短信发送功能
    [asp.net]c# winform打印类
    Exception in thread "main" brut.androlib.AndrolibException: Could not decode arsc file
    ValueError: invalid literal for int() with base 10: 'abc'
    检查网址是否正常访问
    Python测试网络连通性示例【基于ping】
  • 原文地址:https://www.cnblogs.com/penth/p/10209314.html
Copyright © 2011-2022 走看看