2923 -- 【模拟试题】藤原妹红
Description
在幻想乡,藤原妹红是拥有不老不死能力的人类。虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民。由于妹红算得上是幻想乡最强的人类,对于她而言,迷途竹林的单向道路亦可以逆行。在妹红眼中,迷途竹林可以视为一个由N个路口(编号1..N),M条不同长度双向路连接的区域。妹红所在的红之自警队为了方便在迷途竹林中行动,绘制了一张特殊的迷途竹林地图,这张地图上只保留了N-1条道路,这些道路保证了任意两个路口间有且仅有一条路径,并且满足所有保留的道路长度之和最小,我们称这些道路为『自警队道路』。现在妹红打算在其中一个连接有多条『自警队道路』的路口设立根据地,当去掉这个根据地所在路口后,就会出现某些路口间无法通过『自警队道路』相互连通的情况,我们认为这时仍然能够通过『自警队道路』连通的路口属于同一个『区域』。妹红希望最后每个『区域』的『自警队道路』总长尽可能平均,请计算出她应该选择哪一个路口作为根据地。
下例中红色的路口为妹红选择的根据地,实线边表示『自警队道路』,绿色虚线边表示非『自警队道路』,数字表示边权,『自警队道路』中相同颜色的实线边代表属于同一个『区域』:
(尽可能平均即权值最小,设每一块『区域』的路线总长为 Length[i],平均路线长度为Avg=SUM{Length[i]}/区域数,权值d=∑((Length[i]-Avg)^2))
Input
第1行:2个正整数N,M。
第2..M+1行:每行2个整数u,v和1个实数len,表示u,v之间存在长度为len的边。
Output
第1行:1个整数,最后选择的路口编号,存在多个可选路口时选择编号小的。
Sample Input
3 3
3 1 5
3 2 4
1 2 3
Sample Output
2
Hint
【样例解释】
妹红的『固定道路』为(1,2)和(2,3)。只能选择2作为根据地,产生的两个区域Length[i]分别为3和4,所以方差为:(4-3.5)^2+(3-3.5)^2=0.5
【数据范围】
对于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
【注意】
保证不存在相同距离的线路,两个路口间可能出现多条路径,且任意点对间至少存在一条路径。
题解:
树形dp的模板,可以参考树的重心。
首先用Kruskal求出最小生成树,再树形dp就可以了
     最后有大神题解。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define eps 0.0000001
using namespace std;
struct nodee{int fr,to;double v;
}a[200005];
struct node{int to,nxt;double val;
}w[200005];
double sum=0,e[200005],ans=1e80,cur=0,val[200005];
int cnt=0,h[200005],fa[200005],n,m,c1=0,son[200005];
void add(int x,int y,int z)
{cnt++;w[cnt].to=y;w[cnt].nxt=h[x];w[cnt].val=z;h[x]=cnt;
}
bool cmp(nodee a,nodee b)
{return a.v-b.v<eps;
}
int get(int x)
{if(fa[x]==x)return x;return fa[x]=get(fa[x]);
}
void K()
{for(int i=1;i<=n;i++)fa[i]=i;sort(a+1,a+m+1,cmp);for(int i=1;i<=m;i++){int f1=get(a[i].fr),f2=get(a[i].to);if(f1!=f2){fa[f1]=f2,c1++;add(a[i].fr,a[i].to,a[i].v);add(a[i].to,a[i].fr,a[i].v);son[a[i].fr]++,son[a[i].to]++;sum+=a[i].v;}else continue;if(c1==n-1)break;}
}
void dp2(int pos,int fa)
{e[pos]=0;double avg=sum/(1.0*son[pos]);double mine=0;for(int i=h[pos];i;i=w[i].nxt){int j=w[i].to;if(j==fa)continue;dp2(j,pos);val[pos]+=(w[i].val+e[j]-avg)*(w[i].val+e[j]-avg);e[pos]+=(w[i].val+e[j]);mine+=(w[i].val+e[j]);}if(abs(sum-mine)>eps)val[pos]+=(sum-mine-avg)*(sum-mine-avg);if(son[pos]!=1&&(val[pos]-ans<eps||(val[pos]==ans&&pos<cur))){ans=val[pos];cur=pos;}return ;
}
int main(){cin>>n>>m;for(int i=1;i<=m;i++)scanf("%d%d%lf",&a[i].fr,&a[i].to,&a[i].v);K();dp2(1,0);cout<<cur;return 0;
}
附上某大神题解和代码。

【分析】最小生成树 树的遍历

题目大意:给定一个无向有权图,首先一个最小生成树 MST,从 MST 中选取一个度数大于 1 的点 作为根 K,使每颗子树及该子树到根的边权之和方差最小。输出 K 和最小方差的值。

算法1

首先毫无疑问的需要用到求最小生成树的算法,我们考虑使用 Kruskal 算法或是Prim 算法。求出最小生成树以后,依次枚举每一个点作为根进行遍历,取出其中的最小方差即可。

时间复杂度:O(MlogM+N^2)

期望得分:60

算法2

由于后 40%的数据 N 比较大,所以只能通过 Kruskal 算法求出最小生成树,接下来任选一个点作为根,进行一次遍历。记录 w[i]表示以 i 点作为根的子树的边权之和。 然后依次枚举每一个点 i,该点的子树权值可以直接求出,而以它父亲作为根的子树需要特殊处理。这颗特殊子树的权值为最小生成树总权值减去该点权值 w[i]。然后计算出方差,最后选取所有点当中最小方差的那个点即可。

时间复杂度:O(MlogM+N)

期望得分:100
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;#define MAXN 50009
#define MAXE 200009
#define pb(x) push_back(x)
#define mk(x, y) make_pair(x, y)struct EDGE
{int u, v;double length;
}   edge[ MAXE ];
int N, edgecnt;struct Tree
{vector< pair<int, double> > fir[ MAXN ];double Sum, w[ MAXN ];int path[ MAXN ];bool vis[ MAXN ];void Addedge(int u, int v, double length){Sum += length;fir[u].pb( mk(v, length) );fir[v].pb( mk(u, length) );return ;}void DFS(int now){vis[ now ] = true;for (int i = 0; i != fir[now].size(); i++)if (!vis[ fir[now][i].first ]){path[ fir[now][i].first ] = now;DFS( fir[now][i].first );w[now] += fir[now][i].second + w[ fir[now][i].first ];}return ;}void GetAns(){int best(-1);double best_ans(0), tp(0), Avg(0);DFS(1);for (int i = 1; i <= N; i++)if (fir[i].size() > 1){tp = 0;Avg = Sum / fir[i].size();for (int j = 0; j != fir[i].size(); j++)if (fir[i][j].first != path[i])tp += (Avg - fir[i][j].second - w[ fir[i][j].first ]) * (Avg - fir[i][j].second - w[ fir[i][j].first ]);else tp += (Avg - (Sum - w[i])) * (Avg - (Sum - w[i]));if (best == -1 || tp < best_ans)best_ans = tp, best = i;}printf("%d\n", best);return ;}
}   MST;struct Kruskal
{int path[ MAXN ];int Find(int x){if (x != path[x]) path[x] = Find( path[x] );return path[x];}void Input(){scanf("%d %d", &N, &edgecnt);for (int i = 1; i <= edgecnt; i++)scanf("%d %d %lf", &edge[i].u, &edge[i].v, &edge[i].length);return ;}void Work(){int cnt(1), x, y;for (int i = 1; i <= N; i++)path[i] = i;for (int i = 1; i <= edgecnt && cnt < N; i++){x = Find( edge[i].u );y = Find( edge[i].v );if (path[x] == path[y]) continue;path[x] = path[y];MST.Addedge(edge[i].u, edge[i].v, edge[i].length);++cnt;}return ;}
}   Kruskal;bool Comp(EDGE x, EDGE y)
{return x.length < y.length;
}int main()
{Kruskal.Input();sort(edge + 1, edge + edgecnt + 1, Comp);Kruskal.Work();MST.GetAns();return 0;
}

BSOJ2923 CODEVS1419 藤原妹红 最小生成树+树形dp相关推荐

  1. 【codevs1419】藤原妹红 树形DP

    题目描述 Description 在幻想乡,藤原妹红是拥有不老不死能力的人类.虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民.由于算得上是幻想乡最强的人类,对于她而言,迷途竹林的单向道路亦可以逆 ...

  2. CF1120D Power Tree(树形DP/构造+差分+最小生成树)

    解法一:树形DP 个人觉得这个方法是比较可能想到的,但是输出方案很恶心 先转换题意:"无论怎样规定叶子的初始点权,都可以通过操作你选择的点来让所有叶子的点权清空"意味着每个叶子节点 ...

  3. hdu4126(MST + 树形dp

    题意:       这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少. 思路:(prim+树形dp)       先跑一边 ...

  4. hdu4756 最小树+树形dp

    题意:       给你一个完全图,让你在上面找到一颗最小树,然后问破坏这个最小树的某一条边后用其他边连接(要求最小)成新的树,然后输出破坏每一条边后最小树中最大的那个. 思路:       先跑出一 ...

  5. 【XSY2500】都城(树形dp)

    题面 Description Input Output Sample Input 4 1 4 2 4 3 4 Sample Output 2 2 2 3 HINT 题解 考虑到一个性质:任意两个相邻的 ...

  6. BNUOJ 52305 Around the World 树形dp

    题目链接: https://www.bnuoj.com/v3/problem_show.php?pid=52305 Around the World Time Limit: 20000msMemory ...

  7. [树形dp] Jzoj P5233 概率博弈

    Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵n个点的以1为根的有根树,叶子有权值.假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列. 一开始在1号点有 ...

  8. fwt优化+树形DP HDU 5909

    1 //fwt优化+树形DP HDU 5909 2 //见官方题解 3 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ 4 5 #include ...

  9. BZOJ 1040 ZJOI2008 骑士 树形DP

    题目大意:给定一个基环树林,每一个点上有权值,要求选择一个权值和最大的点集,要求点集中的随意两个点之间不能直接相连 最大点独立集--考虑到n<=100W,网络流铁定跑不了,于是我们考虑树形DP ...

最新文章

  1. Netty 采用NIO 而非AIO 的理由
  2. excel如何生成mysql的sql语句_excel 批量生成SQL语句
  3. 复习-arrary和arraylist的对比以及arraylist的遍历中删除的原理
  4. 百货商场如何运用预付费系统进行电能管理呢?
  5. Webtrends收购实时分析公司Reinvigorate
  6. python can通信_Python中的高级/抽象Canbus接口
  7. 动平衡仪制作方法总结
  8. 手机免费logo在线制作的专业教程
  9. 数据科学技术与应用——第2章 多维数据结构与运算
  10. 如何查看所使用计算机的配置,电脑配置的三种查看方法 不用借助软件怎么查看电脑配置...
  11. 是时候拥抱ViewBinding了~
  12. 机器学习与算法(8)--局部加权学习算法(LWR)
  13. 手推优化算法,了解KKT和closed-form solution是如何使用的
  14. JDK1.8 升级这么久!Stream 流的规约操作有哪些?
  15. jquery实现全选
  16. Verdi 知识体系
  17. python人机对话存在的问题_如何适应人机对话要点及情景问题
  18. 2016百度之星 - 初赛(Astar Round2B)1001 1003~1006
  19. 从零开始使用composer开发php项目解决各种包调用
  20. 力扣(LeetCode)剑指offer刷题笔记(java),已完结!!!

热门文章

  1. md文件打开方式推荐
  2. java.commen包的一些用法StringUtils.equals()
  3. 怎样在matlab q-q图上读出斜率,Matlab的常见问题
  4. 基于B/S模式的学生选课系
  5. 7-4 sdust-Java-字符串集合求并集 (20分)
  6. 计算机cpu对什么访问最快,CPU直接访问的存储器是什么?
  7. Cisco测试命令和TCP/IP连接故障处理整理集合
  8. OpenGL Ant Tweak Bar的用户界面库
  9. Unity粒子系统基本
  10. 发那科pmc编程手册_干货|发那科FANUC PMC编程步骤精编版(图文并茂)