最小生成树+DFS求任意两点间平均路径长度 ——Abandoned country (HDU 5732)( 2016Multi-University Training Contest 1 1001 )
2016-07-20 16:27
543 查看
题目链接:
http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1001&cid=704
分析:
点数最大为100000,所以最小生成树应该用Kruskal。因为任意两点的距离不相等,所以最小生成树唯一,那么期望也就是唯一的。而这个期望即任意两点距离的平均值。我们先统计出每条边在所有路径中被用到的次数,用它乘以这条边的权重,加在一块然后除以总路径数(n×(n-1)/2)就能得到结果。
题解:
在kruskal的取边操作里,如果某条边符合条件被选中,这时候加一个操作,把这条边记录到数组里(一条边从两个方向要被记录两次),然后用一个add函数将每条边加入到新的结构体里面,这个结构体的序号是边的序号,里面存储这条边的下一个节点,以及这个边的权重,然后记录这条边的下一条边的序号。
DFS函数:任取一个点作为根节点开始搜索,对每个点i记录其子树包含的点数(包括其自身),设点数为sum[i],则i的父亲一侧的点数即为n-sum[i]。两者相乘就是这条边被用到的次数,边遍历边统计。
P.S. :此处DFS以及add函数的详细分析可以参考 树形DP中的DFS函数与head数组。
DFS 代码:
AC代码:
http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1001&cid=704
分析:
点数最大为100000,所以最小生成树应该用Kruskal。因为任意两点的距离不相等,所以最小生成树唯一,那么期望也就是唯一的。而这个期望即任意两点距离的平均值。我们先统计出每条边在所有路径中被用到的次数,用它乘以这条边的权重,加在一块然后除以总路径数(n×(n-1)/2)就能得到结果。
题解:
在kruskal的取边操作里,如果某条边符合条件被选中,这时候加一个操作,把这条边记录到数组里(一条边从两个方向要被记录两次),然后用一个add函数将每条边加入到新的结构体里面,这个结构体的序号是边的序号,里面存储这条边的下一个节点,以及这个边的权重,然后记录这条边的下一条边的序号。
DFS函数:任取一个点作为根节点开始搜索,对每个点i记录其子树包含的点数(包括其自身),设点数为sum[i],则i的父亲一侧的点数即为n-sum[i]。两者相乘就是这条边被用到的次数,边遍历边统计。
P.S. :此处DFS以及add函数的详细分析可以参考 树形DP中的DFS函数与head数组。
DFS 代码:
struct edge { int from,to,w,next; }e[1000050]; void add(int from,int to,int w) { e[cont].to=to; e[cont].w=w; e[cont].next=head[from]; head[from]=cont++; } ll Dfs(int u) { vis[u]=1; ll cont=1; ll tmp; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; int w=e[i].w; if(vis[v]==0) { tmp=Dfs(v); ans+=tmp*(n-tmp)*1.0*w; cont+=tmp; } } return cont; }
AC代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define N 1000050 using namespace std; typedef long long ll; int f ,Rank ; ll n; int m; struct node { int x,y; ll val; } c ; struct edge { int from,to,w,next; }e[1000050]; bool operator<(node a , node b) { return a.val<b.val; } void init_set() { for(int i=0 ; i<=N ; i++) f[i]=i,Rank[i]=0; } int find_set(int k) { return f[k]=k!=f[k]?find_set(f[k]):f[k]; } void union_set(int x , int y) { x=find_set(x); y=find_set(y); if(x==y) return ; else { if(Rank[x]>Rank[y]) f[y]=x; else if(Rank[y]>Rank[x]) f[x]=y; else Rank[x]++,f[y]=x; } } ll pre[100050]; int head[100050]; int head[100050]; int vis[100050]; int cont; double ans; ll cn2; void add(int from,int to,int w) { e[cont].to=to; e[cont].w=w; e[cont].next=head[from]; head[from]=cont++; } ll Dfs(int u) { vis[u]=1; ll cont=1; ll tmp; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; int w=e[i].w; if(vis[v]==0) { tmp=Dfs(v); ans+=tmp*(n-tmp)*1.0*w; cont+=tmp; } } return cont; } int main() { int T; cin >> T; while(T--) { cont = 0; memset(vis, 0, sizeof(vis)); memset(pre, 0, sizeof(pre)); memset(head, -1, sizeof(head)); scanf("%I64d%d",&n,&m); for(int i=0; i<m; i++) { scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].val); } sort(c,c+m); init_set(); ll output=0; for(int j=0 ; j<m ; j++) { int aa=find_set(c[j].x); int bb=find_set(c[j].y); if(aa!=bb) { union_set(aa,bb); output+=c[j].val; add(c[j].x,c[j].y,c[j].val); add(c[j].y,c[j].x,c[j].val); } } ans=0; cn2=n*(n-1)/2; Dfs(1); printf("%I64d ",output); printf("%.2f\n",ans*1.0/cn2*1.0); } return 0; }
相关文章推荐
- Win2003利用dfs(分布式文件系统)在负载均衡下的文件同步配置方案
- Prim(普里姆)算法求最小生成树的思想及C语言实例讲解
- 详解图的应用(最小生成树、拓扑排序、关键路径、最短路径)
- 最小生成树算法之Prim算法
- 使用C语言实现最小生成树求解的简单方法
- win2003分布式文件系统(dfs)配置方法[图文详解]
- win2003分布式文件系统及其部署 图文教程
- 简单的四则运算
- 数的奇偶性
- ACMer博客瀑布流分析
- ACM程序设计大赛题目分类
- 2015年acm国内排名
- 计算字符串最后一个单词长度
- Hadoop2.6+jdk8的安装部署(1)——使用jar包安装部署【详细】
- 最小生成树算法——Prim和Kruskal算法的实现
- Hadoop FS Shell
- DFS使用方法总结
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫