题目描述
魅力之都是一个有N个路口,M条双向道路连接的城市。警察叔叔绘制了一张特殊的地图,在地图上只保留了N-1条道路,我们称这些道路为【特殊道路】,要保证任意两个路口间有且仅有一条路径,且满足所有保留的道路长度之和最小。现在要在其中一个连接有多条【特殊道路】的路口设立【根据地】,去掉【根据地】所在路口后,就会出现某些路口间无法通过【特殊道路】相互连通的情况,我们认为这时仍然能够通过【特殊道路】连通的路口属于同一个【区域】。警察叔叔希望最后每个【区域】的【特殊道路】总长尽可能平均。警察叔叔找到了hzwer,但是hzwer是个无向图和有向图都无法区分的蒟蒻,请你帮他计算出应该选择哪一个路口作为【根据地】。
(尽可能平均即权值最小,设每一块【区域】的路线总长为Length[i](包括连接【根据地】与该【区域】的边),平均路线长度为Avg=SUM{Length[i]}/区域数,权值d=∑ (Length[i]-Avg)^2
输入格式
第1行:2个正整数N,M第2..M+1行:每行2个整数u,v和1个实数len,表示u,v之间存在长度为len的边
输出格式
第1行:1个整数,最后选择的路口编号(存在多个可选路口时选择编号小的)样例数据 1
输入3 3
3 1 5
3 2 4
1 2 3
输出
2
样例数据 2
输入3 3
2 1 825.7291
3 2 397.4120
1 3 633.1370
输出
3
备注
对于60%的数据:3 ≤ N ≤ 2,000,N-1 ≤ M ≤ 50,000对于100%的数据:3 ≤ N ≤ 40,000,N-1 ≤ M ≤ 200,000
对于100%的数据:0 < len ≤ 100,000,000
保证不存在相同距离的线路,两个路口间可能出现多条路径,且任意点对间至少存在一条路径
题解
话说第一步是最小生成树没人不知道。n挺小的,dfs求出树上一些信息,枚举每个点即可。
考试时逗了,rest忘清零了……
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MAXM 200002
#define MAXN 40002
using namespace std;
int n,m,f[MAXN];
struct bian{int x,y; double v;} E[MAXM];
double totlen;
int zz,head[MAXN],fa[MAXN],con[MAXN],ans;
struct tree{int to,nx; double v;} e[MAXM*2];
double sum[MAXN],mind,pjlen,d,rest;
//------------------------------------------------------------------------------
bool kp(const bian &i,const bian &j) {return i.v<j.v;}
void init()
{
scanf("%d%d",&n,&m);
int i,x,y; double z;
for(i=1;i<=m;i++)
scanf("%d%d%lf",&E[i].x,&E[i].y,&E[i].v);
sort(E+1,E+m+1,kp);
}
void insert(int x,int y,double z)
{
zz++; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;
zz++; e[zz].to=x; e[zz].v=z; e[zz].nx=head[y]; head[y]=zz;
}
int find(int x)
{
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
void klskl()
{
int i,r1,r2;
for(i=1;i<=n;i++) f[i]=i;
for(i=1;i<=m;i++)
{r1=find(E[i].x),r2=find(E[i].y);
if(r1!=r2)
{f[r2]=r1; totlen+=E[i].v;
insert(E[i].x,E[i].y,E[i].v);
}
}
}
//------------------------------------------------------------------------------
void dfs(int x)
{
int i,p;
con[x]=1;
if(x==1) con[x]--;
for(i=head[x];i;i=e[i].nx)
{p=e[i].to;
if(p==fa[x]) continue;
sum[p]+=e[i].v; con[x]++;
fa[p]=x; dfs(p);
sum[x]+=sum[p];
}
}
double sqr(double x) {return x*x;}
void work()
{
int i,j,p;
mind=1e20;
for(i=1;i<=n;i++)
{if(con[i]<=1) continue;
d=0; pjlen=totlen/con[i]; rest=0;
for(j=head[i];j;j=e[j].nx)
{p=e[j].to;
if(p==fa[i]) continue;
d+=sqr(sum[p]-pjlen);
rest+=sum[p];
}
rest=totlen-rest;
d+=sqr(rest-pjlen);
if(d<mind)
{mind=d; ans=i;}
}
printf("%d\n",ans);
}
int main()
{
init(); klskl();
dfs(1); work();
return 0;
}