BSOJ2923 CODEVS1419 藤原妹红 最小生成树+树形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)
#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相关推荐
- 【codevs1419】藤原妹红 树形DP
题目描述 Description 在幻想乡,藤原妹红是拥有不老不死能力的人类.虽然不喜欢与人们交流,妹红仍然保护着误入迷途竹林村民.由于算得上是幻想乡最强的人类,对于她而言,迷途竹林的单向道路亦可以逆 ...
- CF1120D Power Tree(树形DP/构造+差分+最小生成树)
解法一:树形DP 个人觉得这个方法是比较可能想到的,但是输出方案很恶心 先转换题意:"无论怎样规定叶子的初始点权,都可以通过操作你选择的点来让所有叶子的点权清空"意味着每个叶子节点 ...
- hdu4126(MST + 树形dp
题意: 这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少. 思路:(prim+树形dp) 先跑一边 ...
- hdu4756 最小树+树形dp
题意: 给你一个完全图,让你在上面找到一颗最小树,然后问破坏这个最小树的某一条边后用其他边连接(要求最小)成新的树,然后输出破坏每一条边后最小树中最大的那个. 思路: 先跑出一 ...
- 【XSY2500】都城(树形dp)
题面 Description Input Output Sample Input 4 1 4 2 4 3 4 Sample Output 2 2 2 3 HINT 题解 考虑到一个性质:任意两个相邻的 ...
- BNUOJ 52305 Around the World 树形dp
题目链接: https://www.bnuoj.com/v3/problem_show.php?pid=52305 Around the World Time Limit: 20000msMemory ...
- [树形dp] Jzoj P5233 概率博弈
Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵n个点的以1为根的有根树,叶子有权值.假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列. 一开始在1号点有 ...
- fwt优化+树形DP HDU 5909
1 //fwt优化+树形DP HDU 5909 2 //见官方题解 3 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ 4 5 #include ...
- BZOJ 1040 ZJOI2008 骑士 树形DP
题目大意:给定一个基环树林,每一个点上有权值,要求选择一个权值和最大的点集,要求点集中的随意两个点之间不能直接相连 最大点独立集--考虑到n<=100W,网络流铁定跑不了,于是我们考虑树形DP ...
最新文章
- Netty 采用NIO 而非AIO 的理由
- excel如何生成mysql的sql语句_excel 批量生成SQL语句
- 复习-arrary和arraylist的对比以及arraylist的遍历中删除的原理
- 百货商场如何运用预付费系统进行电能管理呢?
- Webtrends收购实时分析公司Reinvigorate
- python can通信_Python中的高级/抽象Canbus接口
- 动平衡仪制作方法总结
- 手机免费logo在线制作的专业教程
- 数据科学技术与应用——第2章 多维数据结构与运算
- 如何查看所使用计算机的配置,电脑配置的三种查看方法 不用借助软件怎么查看电脑配置...
- 是时候拥抱ViewBinding了~
- 机器学习与算法(8)--局部加权学习算法(LWR)
- 手推优化算法,了解KKT和closed-form solution是如何使用的
- JDK1.8 升级这么久!Stream 流的规约操作有哪些?
- jquery实现全选
- Verdi 知识体系
- python人机对话存在的问题_如何适应人机对话要点及情景问题
- 2016百度之星 - 初赛(Astar Round2B)1001 1003~1006
- 从零开始使用composer开发php项目解决各种包调用
- 力扣(LeetCode)剑指offer刷题笔记(java),已完结!!!
热门文章
- md文件打开方式推荐
- java.commen包的一些用法StringUtils.equals()
- 怎样在matlab q-q图上读出斜率,Matlab的常见问题
- 基于B/S模式的学生选课系
- 7-4 sdust-Java-字符串集合求并集 (20分)
- 计算机cpu对什么访问最快,CPU直接访问的存储器是什么?
- Cisco测试命令和TCP/IP连接故障处理整理集合
- OpenGL Ant Tweak Bar的用户界面库
- Unity粒子系统基本
- 发那科pmc编程手册_干货|发那科FANUC PMC编程步骤精编版(图文并茂)