[BZOJ4061][Cerc2012]Farm and factory

bzoj
鉴于是权限题,放一下题面。

Description

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

Input

第一行一个正整数\(T\),表示有\(T\)组数据。
每组数据第一行两个正整数\(n\)\(m\),表示Byteland有\(n\)个城市和\(m\)条道路,\(2\le n\le10^5,1\le m\le3\times10^5\)
接下来\(m\)行,每行三个整数表示城市\(u\)和城市\(v\)之间有一条过路费为\(c\)的道路,\(1\le u,v \le n,u\neq v, 0\le c\le 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

sol

最小化平均过路费就是最小化总过路费。
我们设从\(1\)出发到每个点的最短路是\(f[i]\),从\(2\)出发到每个点的最短路是\(g[i]\),从新点出发到每个点的最短路是\(s[i]\)。新点到\(1,2\)号点的最短路是\(A,B\)
为了保证最短路不经过新点,就需要满足:\(s_i+A\ge f_i,s_i+B\ge g_i\)
同时根据最短路的定义,有\(s_i+f_i\ge A,s_i+g_i\le B\)
我们要最小化\(\sum s_i\),所以\(s_i=\max(|A-f_i|,|B-g_i|)\)
发现是个切比雪夫距离的式子,所以直接排个序取中位数即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
#define ll long long
#define pi pair<ll,int>
#define mk make_pair
const int N = 1e5+5;
const int M = 6e5+5;
int T,n,m,to[M],nxt[M],ww[M],head[N],cnt,vis[N];
ll f[N],g[N];
priority_queue<pi,vector<pi>,greater<pi> >Q;
void link(int u,int v,int w){
	to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
}
void Dijkstra(int s,ll *dis){
	memset(vis,0,sizeof(vis));
	dis[s]=0;Q.push(mk(0,s));
	while (!Q.empty()){
		int u=Q.top().second;Q.pop();
		if (vis[u]) continue;vis[u]=1;
		for (int e=head[u];e;e=nxt[e])
			if (dis[to[e]]>dis[u]+ww[e])
				dis[to[e]]=dis[u]+ww[e],Q.push(mk(dis[to[e]],to[e]));
	}
}
int main(){
	T=gi();while (T--){
		n=gi();m=gi();
		memset(head,0,sizeof(head));cnt=0;
		for (int i=1;i<=m;++i){
			int u=gi(),v=gi(),w=gi();
			link(u,v,w);link(v,u,w);
		}
		memset(f,63,sizeof(f));memset(g,63,sizeof(g));
		Dijkstra(1,f);Dijkstra(2,g);
		for (int i=1;i<=n;++i){
			ll x=f[i],y=g[i];
			f[i]=x+y,g[i]=x-y;
		}
		sort(f+1,f+n+1);sort(g+1,g+n+1);f[0]=g[0]=0;
		for (int i=1;i<=n;++i) f[i]+=f[i-1],g[i]+=g[i-1];
		if (n&1) printf("%.8lf\n",1.0*(f[n]-f[n/2]-f[n/2+1]+g[n]-g[n/2]-g[n/2+1])/(2.0*n));
		else printf("%.8lf\n",1.0*(f[n]-2*f[n/2]+g[n]-2*g[n/2])/(2.0*n));
	}
	return 0;
}
posted @ 2018-06-25 22:39  租酥雨  阅读(316)  评论(0编辑  收藏  举报