【bzoj4061: [Cerc2012]Farm and factory】

4061: [Cerc2012]Farm and factory

Time Limit: 10 Sec   Memory Limit: 128 MBSec   Special Judge
Submit: 172   Solved: 54
[ Submit][ Status][ Discuss]

Description

向Byteland的国王Bitolomew致敬!国王Bitolomew认为Byteland是一个独一无二的国家。它太小了,它所有的市民(包括国外)都只在农场或工厂之一工作,其中农场和工厂是两个不同的城市。因此每天早晨,每个城市的居民都在去这两个城市的路上通行。Byteland的交通网络包括一些连接两个不同城市的无向的道路,道路不会连向国家之外的城市(但是隧道和桥可能会这样)。两个城市间可能存在多条无向的道路。保证农场和工厂与所有城市连通。几个月前,为了改善交通状况,国王Bitolomew出台了过路费的政策,需要每个市民每次在通过相应道路时支付固定的费用Bitolomew希望这能引导市民重新考虑他们的上班路线,从而使得交通更加均匀畅通。国王的点子被他的谏者证明是不够完美的。每个Byteland的市民现在都开始走起了最便宜的上班路线。国王Bitolomew完全没想到会出现这种情况,然而过路费带来的收入着实提高了国家财政的收入。事实上,国王现在的经济状况实在是太好了,所以他准备在一个新的首都建一个新的城堡。新的首都必须和一些其他的城市通过无向的道路相连,这样才能从新首都到达每个城市。新建的道路可以设定非负的过路费(特别地,这里的过路费可以不是整数)。国王Bitolomew真的很讨厌车辆路过他的城堡所产生的噪声。他希望通过合理设定新道路的过路费使得从任意除了新首都之外的城市v到农场或工厂都不会经过新首都(注意这里v还包括农场和工厂)。另外,由于国王也要交过路费,所以他希望最小化从新首都到其他每个城市的平均过路费。请你帮助国王计算一下最小可能的平均值是多少吧。

Input

第一行一个正整数T,表示有T组数据。

每组数据第一行两个正整数n和m,表示Byteland有n个城市和m条道路,2 <= n <= 10^5,1 <= m <= 3*10^5。
接下来m行,每行三个整数表示城市u和城市v之间有一条过路费为c的道路,1 <= u, v <= n,u ≠ v,0 <= c <= 10^6。两个城市间可能存在多条无向的道路。
农场所在的城市标号为1,工厂所在的城市标号为2。

Output

 对于每组数据输出一行,最小可能的从新首都到其他点所需过路费的平均值。

你的答案应该和标准答案误差不超过10^-8。

Sample Input

1
3 3
1 2 5
2 3 5
3 1 1

Sample Output

1.833333333333


用x表示新首都,dis[i][j]表示原图中的i到j的最短路,dis1[i][j]表示加入新首都后的最短路情况。

由于不能经过x点,所以:

dis1[1][x]+dis1[x][i]>=dis[1][i];

又由于最短路的定义,所以:

dis[1][i]+dis1[i][x]>=dis1[1][x];

综合得到 dis1[x][i]>=|dis[1][i]-dis1[1][x]|

同理 dis1[x][i]>=|dis[2][i]-dis1[2][x]|

最后求的是 ∑(dis1[x][i])最小,所以dis1[x][i]=max(|dis[1][i]-dis1[1][x]|,|dis[2][i]-dis1[2][x]|)。

这就是切比雪夫距离,切比雪夫距离转化为曼哈顿距离:

max(|x1x2|,|y1y2|)=max(x1x2,x2x1,y1y2,y2y1);

令 x3=x1+y1,y3=x1-y1,x4=x2+y2,y4=x2-y2;

max(|x1x2|,|y1y2|)=max(x3x4+y3y4x4x3+y3y4,x3x4+y4y3,x4x3+y4y3)/2

=|x3-x4|+|y3-y4|

然后就可以求中位数了。


#include <bits/stdc++.h>
#define ll long long
#define INF (ll) 1e15
#define N 100005
#define M 600005
using namespace std;
struct he{
	int nx,r,c;
}a[M];
int fir[N],k,n,u,v,c,vis[N],T,m,sz,pos[N];
ll dis[3][N],x[N],y[N];
struct ha{
	ll d;
	int p;
}h[N];
double ans;
void init(){
	for(int i=0;i<=n;i++) fir[i]=-1;
	k=0;
	sz=0;
	ans=0.0;
}
void add(int l,int r,int c){
	k++;a[k].c=c;a[k].nx=fir[l];a[k].r=r;fir[l]=k;
}
void down(int p){
	int p1=p<<1;
	if(p1>sz) return ;
	if(p1+1<=sz&&h[p1+1].d<h[p1].d) p1++;
	if(h[p1].d<h[p].d){
		swap(pos[h[p1].p],pos[h[p].p]);
		swap(h[p1].d,h[p].d);
		swap(h[p1].p,h[p].p);
		down(p1);
	}
}
void up(int p){
	if(p==1) return ;
	int p1=p>>1;
	if(h[p1].d>h[p].d){
		swap(pos[h[p1].p],pos[h[p].p]);
		swap(h[p1].d,h[p].d);
		swap(h[p1].p,h[p].p);
		up(p1);
	}
}
void insert(int x,ll d){
	sz++;
	h[sz].p=x;h[sz].d=d;pos[x]=sz;
	up(sz);
}
void dij(int st){
	for(int i=1;i<=n;i++) dis[st][i]=INF;
	dis[st][st]=0;
	insert(st,0);
	for(int i=0;i<=n;i++) vis[i]=0;
	for(int i=1;i<=n;i++){
		int x=h[1].p;h[1].d=INF;down(1); 
		for(int j=fir[x];j!=-1;j=a[j].nx)
		if(dis[st][x]+a[j].c<dis[st][a[j].r]){
			dis[st][a[j].r]=dis[st][x]+a[j].c;
			if(!vis[a[j].r]) {
				insert(a[j].r,dis[st][a[j].r]);
				vis[a[j].r]=1;
			}	else h[pos[a[j].r]].d=dis[st][a[j].r];
			up(pos[a[j].r]);
		}
	}
}
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	T=_read();
	while(T--){
		n=_read();m=_read();
		init();
		for(int i=1;i<=m;i++){
			u=_read();v=_read();c=_read();
			add(u,v,c);add(v,u,c);
		}
		dij(1);sz=0;dij(2);	
		for(int i=1;i<=n;i++)
			x[i]=dis[1][i]+dis[2][i],y[i]=dis[1][i]-dis[2][i];
		sort(x+1,x+1+n);sort(y+1,y+1+n);
		ll x1=x[(n+1)/2],y1=y[(n+1)/2];
		for(int i=1;i<=n;i++)
			ans+=abs(x1-x[i])+abs(y1-y[i]);
		printf("%.12lf\n",ans/(2.0*n)); 
	}
}


m a x ( x3 x4 + y3 y4 x4 x3 + y3 y4 , x3 x4 + y4 y3 , x4 x3 + y4 y3 )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值