Abandoned country
题目链接
题目大意
有一个村子里面修公路,每条公路都有一个修建价值,现在让你把所有村子连起来,求最小价值,顺便求出所有公路的平均值。
题解
最小生成树+DFS
首先肯定是一个最小生成树了,主要是求所有路径的平均值。
可以看到是一颗树,想到在DFS的同时记录数据来求这颗树的所有路径和,我们画图发现,当前边对sum的贡献是
当前节点数⋅当前边权值+父节点到其他所有节点的路径和
所以我们记录一个
last:父节点到其他所有节点的路径和
每次求完一颗子树的时候加进总结过就行了。
这个题方法挺多的,好像还看到有人用DP?
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxm 1000010
#define maxn 100010
#define LL long long
using namespace std;
struct edge
{
int u,v,next,d;
bool operator<(const edge &x) const
{
return d<x.d;
}
};
edge e[maxm<<1],E[maxm<<1];
int pre[maxn],nume,numE,f[maxn];
LL T,n,m;
LL sum,tag;
void addedge(edge e[],int u,int v,int d,int &nume)
{
e[nume].u=u;
e[nume].v=v;
e[nume].d=d;
e[nume].next=pre[u];
pre[u]=nume++;
}
int getfather(int k)
{
if (f[k]==k) return k;
else return f[k]=getfather(f[k]);
}
LL dfs(int u,int father,LL dis,LL last)
{
LL p=0,c,flag=tag+1;
sum+=last;
last+=tag*dis;
tag++;
for (int i=pre[u];i!=-1;i=E[i].next)
{
int v=E[i].v;
if (v!=father)
{
sum+=(tag)*E[i].d;
c=dfs(v,u,E[i].d,last+p);
p+=c+(tag-flag)*E[i].d;
flag=tag;
}
}
return p;
}
int main()
{
scanf("%I64d",&T);
while (T--)
{
memset(f,0,sizeof(f));
memset(e,0,sizeof(e));
memset(pre,-1,sizeof(pre));
memset(E,0,sizeof(E));
nume=0; numE=0; sum=0; tag=0;
int u,v,fu,fv,d;
scanf("%I64d%I64d",&n,&m);
for (int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&d);
addedge(e,u,v,d,nume);
addedge(e,v,u,d,nume);
}
sort(e,e+nume);
LL ans=0;
for (int i=0;i<=n;i++) f[i]=i;
memset(pre,-1,sizeof(pre));
for (int i=0;i<nume;i++)
{
u=e[i].u; v=e[i].v;
fu=getfather(u); fv=getfather(v);
if (fu!=fv)
{
f[fv]=fu; ans+=e[i].d;
addedge(E,u,v,e[i].d,numE);
addedge(E,v,u,e[i].d,numE);
}
}
dfs(1,0,0,0);
LL nn= (n-1)*n/2;
double exp=(double) sum/nn;
printf("%I64d %.2lf\n",ans,exp);
}
return 0;
}