2017多校联合第三场 1005题 hdu 6060 RXD and dividing (超详细!!!)构造

HDU1005 ACM ICPC HDOJ 1005 立即下载

题目链接


题意:

给定一棵 n 个节点的树,1 为根。现要将节点 2 ~ n 划分为 k 块,使得每一块与 根节点 形成的最小斯坦纳树的 边权值 总和最大。


看了题解之后的思考:

题解是:记有向边 (u, v) 长度为 w[v],以点 v 为根的子树的节点总数为 sz[v],那么答案就是 w[v] * min(sz[v], k) 对每个点求个和。

题解的说法是:可以通过构造使得 balabala...

http://bestcoder.hdu.edu.cn/blog/2017-multi-university-training-contest-3-solutions-by-%E6%B4%AA%E5%8D%8E%E6%95%A6/


一开始觉得...这简直是在开玩笑吧。后来仔细画画图,好像真是这么回事。原来之前思考的时候一直陷入了一个误区,至于是什么,我们之后再说。

现在,先来谈一谈,究竟如何构造。


首先,入手点是 每条边 被算了多少次,即每条边的权值对最终答案的贡献。(这种看贡献的想法真的很重要(敲黑板))

其次,从题解中我们可以发现,这个算了多少次 好像就 简简单单地 取了 可能取到的最大值。

然而,这个尽可能的能被允许的最大值 min(sz[v], k) 能保证在每个点都一定能取到吗?

答案是可以的。


首先,要明确的是,对于以 v 为根的子树而言,将其划分的块数越多,对 w[v] 的贡献就越大。

下面开始分类讨论。

1. 

当除根以外所有节点的 sz 值 都 <= k 时,对于任意一个点 v,可将以 v 为根的子树划分为 sz 块,此时贡献最大。

对于任意两个点 v1,v2 而言:

1)若 v2 在 以 v1 为根的子树内(v1 在以 v2 为根的子树内 同理),可将 v1 看成一个整体,其中 sz1 个点划分为 sz1 块即可

2)若 v2 不在以 v1 为根的子树内,且 v1 不在以 v2 为根的子树内,那么 v1 的 sz1 块 与 v2 的 sz2 块就是完全独立的,可以简单地将 sz1 中的任一个集合 与 sz2 中的任一个集合合并,只要保证 sz1 中不同的集合 不与 sz2 中的同一个集合合并, sz2 中不同的集合 也不与 sz1 中的同一个集合合并 即可(其他合并方式也可以,如使 其中一块 自成一个集合等等,只要满足前述条件 并且 合并后的总数 <= k 即可)

反复进行上述操作,最终可得到 sz (sz <= k) 块,并且其中每一步都取了尽可能的最大值

2. 

存在节点 u,其 sz 值 > k,

对于 u 节点与另外一点 v 而言:

1)若 v 在以 u 为根的子树中,显然,u 必有 sz 值 <= k 的孩子节点,若 v 不是,则可递归地再往下找。

不妨就设其为 v,则 v 的 sz 值 <= k,并且已经被划分好为 szv 块。那么,对于 u 的其他没有被划分的孩子节点,只需将 szu - szv 个节点划分为 k - szv 块即可。

2)若 v 不在以 u 为根的子树中,u 也不在以 v 为根的子树中,合并方式同 1. 2) 相同

反复进行上述操作,最终可得到 k 块,并且其中每一步都取了尽可能的最大值


综上,可以构造出这样的集合使得答案取到最大值。



反思:

一开始思维局限在了每一个子树内要划分出一个集合,压根没想到可以把(相对)不相干的点塞到同一个集合中,主要还是受没改题面之前要求 最小值 的影响...

再提一提最小值怎么做吧,学姐给出的做法是,将根节点到其余每个节点的距离从小到大排个序(包括1到1的距离0),要注意的是,节点有几个子树就把这段距离算几遍,用bfs+贪心(优先队列),取前 k 个最小的,然后加上树上本身每条边的权值,即为答案。



后话:

看了题解后写了一个 dfs,结果用测试数据测结果卡了...一狠心在 hdu 上交了一遍竟然 AC 了。跑去看了 std,回来乖乖地又写了一遍 bfs,然后测试数据就也能跑通了...真是......厉害了。第一场的 12 题也是这样,总都是搞得深度很深来卡递归,也是...没办法了Orz

(后面的代码上面 bfs 和 dfs 都有)



AC代码如下:

#include <bits/stdc++.h>
#define maxn 1000010
int ne[maxn], sz[maxn], w[maxn], n, k, tot, q[maxn], fa[maxn];
bool vis[maxn];
inline min(int a, int b) { return a < b ? a : b; }
typedef long long LL;
struct Edge {
    int to, dist, ne;
    Edge(int a = 0, int b = 0, int c = 0) : to(a), dist(b), ne(c) {}
}edge[maxn * 2];
void add(int x, int y, int d) {
    edge[tot] = Edge(y, d, ne[x]);
    ne[x] = tot++;
}
void dfs(int u, int fa) {
    sz[u] = 1;
    for (int i = ne[u]; i != -1; i = edge[i].ne) {
        Edge e = edge[i]; int v = e.to;
        if (v == fa) continue;
        w[v] = e.dist;
        dfs(v, u);
        sz[u] += sz[v];
    }
}
void bfs(int src) {
    memset(vis, 0, sizeof(vis));
    int f = 0, r = 0;
    q[r++] = src; vis[src] = true;
    while (r > f) {
        int u = q[f]; sz[u] = 1;
        ++f;
        for (int i = ne[u]; i != -1; i = edge[i].ne) {
            Edge e = edge[i]; int v = e.to;
            if (vis[v]) continue;
            q[r++] = v; vis[v] = true;
            fa[v] = u; w[v] = e.dist;
        }
    }
    for (int i = r - 1; i >= 0; --i) sz[fa[q[i]]] += sz[q[i]];
}
void work() {
    memset(ne, -1, sizeof(ne));
    tot = 0;
    for (int i = 1; i < n; ++i) {
        int x, y, d;
        scanf("%d%d%d", &x, &y, &d);
        add(x, y, d);
        add(y, x, d);
    }
//    dfs(1, -1);
    bfs(1);
    LL ans = 0;
    for (int i = 2; i <= n; ++i) {
        ans += (LL)w[i] * min(sz[i], k);
    }
    printf("%lld\n", ans);
}
int main() {
    while (scanf("%d%d", &n, &k) != EOF) work();
    return 0;
}



SAR成像系列:【3】合成孔径雷达(SAR)的二维回波信号与简单距离多普勒(RD)算法 (附matlab代码) 二维回波信号分析 阅读详情

相关推荐

相机标定-机器视觉基础(理论推导、Halcon和OpenCV相机标定)

相机标定是获得目标工件精准坐标信息的基础。首先,必须进行相机内参标定,构建一个模型消除图像畸变;其次,需要对相机和机器人的映射关系进行手眼标定,构建一个模型将图像坐标系上的点映射到世界坐标系。主要分为背景知识、相机内外参模型推导、编程代码实现三个部分。

beyond951的博客 7302

hdu1005(循环节)

点击打开链接 题目意思很简单,递推求fn,但是由于给出的数据比较大,直接用for循环肯定超时,这就不得不考虑循环的问题了,由于fn对7取余,所以其取值只能是0,1,2,3,4,5,6这七个数,所以递推求得的fn只能有7*7=49种可能,第五十个数肯定会循环前49个数的一部分,这里要注意,循环节不一定是从1 ,1,开始的。 c代码: #include #include int f[50];

小超人的专栏 694

打开LWIP_DEBUG的打印信息调试

在lwip 2.1.2的版本,打开的debug 调试的步骤: 1.在debug.h 文件中找到debug打印的定义 默认LWIP_DEBUG这个宏没有定义, 2.在lwipopt.h 文件中或者其他文件定义 一下LWIP_DEBUG这个宏, 3.在opt.h 中可以打开各种宏的调试信息, /* --------------------------------------- ---------- Debugging options ---------- ---------...

haidscs的博客 9879

HDU1005解析

题目大意: 有这样一个数列f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.给我们a和b求f(n)的值。 题目分析: 试错分析 这是一道很有意思的题目本着做完之后去看看别人解析的习惯我发现大多数的分析情况都考虑的不够全面所以就写下了这篇博客。 试错:看到这个题目的第一眼首先想到了,直接递归求解,看了一眼数据大小明显递归会炸,于是我又考虑记忆化搜索,但是n的大小在10^8很明显如果采用记忆化搜索这道题一定会炸,所以肯定也不行。 于是看

qq_14881791的博客 413

AI 编程助手新玩法:用 Claude Code 一键调用国产大模型(DeepSeek/Kimi/GLM 对比)

本文深入评测了Claude Code与三大国产大模型(DeepSeek、Kimi、智谱GLM)的集成效果,详细对比了它们在代码生成质量、响应速度和特殊场景支持度等方面的差异。通过实测数据和实战技巧,帮助开发者选择最适合的AI编程助手组合,提升开发效率。

weixin_30955617的博客 487

Abel逆变换及其求解方法

Abel逆变换常应用在轴对称的、光学薄的火焰、羽流或等离子体重建。

weixin_49783507的博客 8370

HDU-1005-题解-思维

HDU 1005 题解 Number Sequence 题目大意 数列 类似于斐波那契的模7数列 f(1) = f(2) = 1 f(n) = (a * f(n - 1) + b * f(n - 2)) % 7 Time: 1000 ms Memory: 32768 kB 解题思路及分析 1<=n<=100,000,0001 <= n <= 100,000,0001<=n<=100,000,000 直接开数组会MLE 不开数组用三个数迭代模拟会TLE .

CapriceH的博客 476

ubuntu20.04运行VINS-Mono(跑EuRoC数据集)

在VINS-Mono主工程目录下的config子目录中找到euroc文件夹,并打开其中的euroc_config.yaml文件,将其中结果输出保存路径修改为本地的绝对路径或相对路径。应该是这个功能包路径没有成功得到,直接注释了这一行,改成你电脑中安装的vins_mono的pose_graph这个功能包路径,备注:直接下可能因为包太大下不下来,我是下载的zip,再解压,将VINS-Mono-master重命名为VINS-Mono。,当时参考了几篇不同的文章,感觉我的这个配置应该也可以编译,就先尝试了一下。

2301_80311277的博客 2978

ACM-HDU-1005 WA

ACM-HDU-1006 思路:因为n<=100000000,所以无论用单纯的递归,还是dp(可能是我的代码太菜了…),都不行,这道题需要知道:f[x]只能取0~6的值,但是f[x]是由f[x-1]与f[x-2]与A,B决定的,所以组合的方式就7*7=49种,用鸽巢定理(m+1个苹果放m个抽屉,必然要有一个抽屉至少是2个苹果),也就是无论如何到f[50]的时候f[48]与f[49]必然是出现过得f[x-1]与f[x-2],后面自然是循环的过程,所以需要找到循环节,答案自然而然就出来了. 代码: #in

奋斗小白的博客 333

在游戏开发中如何使用Unity3D引擎开发麻将游戏

总体来说使用Unity3D引擎开发麻将游戏需要开发人员熟练掌握Unity3D的各种功能和API,并且需要深入了解麻将游戏的规则和背景,以便实现一个质量高、玩法丰富的游戏。在测试的过程中我们需要检查游戏是否符合规则,保证游戏逻辑的正确性,并检查游戏的UI是否和设计图一致,保证游戏的可玩性。Unity3D引擎是一个高度集成的游戏开发工具,可以为开发人员提供很多强大的工具和功能,包括3D建模、物理模拟、粒子系统、动画等等,在游戏开发中可以提高开发效率和游戏质量。在开始开发之前我们需要明确游戏的需求和功能。

a272857154的专栏 1889

IEC61850规约客户端软件开发实战(第六章)

IEC 61850标准中的GOOSE(Generic Object Oriented Substation Event,面向通用对象的变电站事件)功能是变电站自动化系统的核心通信机制,主要用于实现智能电子设备(IED)间高可靠性、低延时的实时信号传输。本章简述其核心功能与技术特点。

半青年的博客 1778

hdu 1005

题目大意:中文题,可以直接在OJ上看 解题思路:本题如果直接递归的话很有可能会OVER STACK。 1)本题的关键是找到循环节,即(arr[i] == 1 && arr[i - 1] == 1) 2) 又是一道给出了运算公式的数学凡是没有优化的话,超时超内存等等是避免不了的了。这题很显然是一个找规律的题目,也就是该题的求解中是存在循环节的。对于公式 f[n] = A * f[n-

黄俊东的专栏 2794

196、NPU的编译器开发:教程与示例代码编写

NPU编译器开发实战指南 摘要:本文分享了NPU编译器开发中的核心挑战与实战经验,通过具体代码示例展示了关键实现技术: 指令生成:必须考虑硬件特性(如地址对齐)和芯片配置抽象化 图优化:重点处理常见冗余结构(Reshape合并、BN融合),并注意数值稳定性 算子拆分:采用分块计算策略适配有限SRAM,需特别注意边界条件处理 内存分配:基于张量使用频率的贪心算法优化SRAM使用效率 文中包含多个真实踩坑案例: DMA地址未对齐导致硬件错误 BN融合时的除零风险 tile边界处理不当引起的精度下降 这些经验为开

m0_50546716的博客 79

2017年多校联合训练 第三场(洪华敦)

Link 官方题解1003 Kanade’s sum hdoj6058题目链接 暴力可过#include<bits/stdc++.h> using namespace std; #define N 500005 int t,n,k,i,j,a[N],b[N],c[N],p,q; long long s; int main() { scanf("%d",&t); while(t-

qyq 1424

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

hdu6060-思维&搜索&好题-RXD and dividing

http://acm.hdu.edu.cn/showproblem.php?pid=6060 给定一个树,问你把除了1节点之外的节点 分成k份,然后让每一份和1节点 连接成 最小的斯坦纳树(最小生成树是一种特殊的斯坦纳树,所以斯坦纳树就是把所有的节点连通的树。),而图中已经是树了,所以其实就是把他们连接起来(就是题中对应的f函数,但是已经是树了所以不存在最小一说。。连起来只有一种情况啊)。问你最大

天与云与山与水 445

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Hdu6060 RXD and dividing(2017多校第3场)

RXD and dividing Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 674    Accepted Submission(s): 290 Problem Description RXD has a

Jelly_acm的博客 740

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

hdu6060 一次就懂 dfs+思维 多校第三场1005

题意 给出一颗n个节点的树,要求将2-n号节点分成k个集合,然后对于每个集合加上1号节点算一个联通的最小花费(最小斯坦纳树),定义为每一部分的value,问总的value最大可能是多少。题解 因为给出的n个节点本身满足是一个树,所以对于每个集合求的最小斯坦纳树其实就是最小生成树就是在给出树中联通集合所有节点加上1号节点的所有边权和。 因为每个集合都包含1这个点,因此对于每个点都至少有一条到1的

WilliamSun0122的博客 578

【HDU6060】RXD and dividing(dfs)

RXD has a tree T, with the size of n. Each edge has a cost. Define f(S) as the the cost of the minimal Steiner Tree of the set S on tree T. he wants to divide 2,3,4,5,6,…n into k parts S1,S2,S3,…Sk, where

No Program No Life 503

HDU6060-RXD and dividing

RXD and dividingTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 65 Accepted Submission(s): 15Problem Description RXD has a tree T, with t

algzjh的博客 1166

HDU6060-RXD and dividing 简单树形DP+贪心

传送门 题意: 给了一棵以1为原点,n个点的树,然后将其余的n-1个点分成k个部分,每个部分又都是以1为根的最小斯坦纳树,求k个最小斯坦纳树的边权最大总值。 思路: 1、由于是在一棵树上选边,所以其实不存在建最小斯坦纳树的问题; 2、贪心的思想,对于每一条边,方向为从父节点到子节点,其所能达到的最大贡献为,len * Max(k,son_node);

survivorone的博客 486

HDU 6060 RXD and dividing [想法题]

HDU 6060 RXD and dividing [想法题]

ACTerminate的博客 823

HDU-6060 RXD and dividing - 2017 Multi-University Training Contest - Team 3(思维+最小斯坦纳树)

RXD has a tree TT, with the size of nn. Each edge has a cost. Define f(S)f(S) as the the cost of the minimal Steiner Treeof the set SS on tree TT. he wants todivide2,3,4,5,6,n2,3,4,5,6,…n into kk parts S1,S2,S3,…SkS1,S2,S3,…Sk, where ⋃Si={2,3,…,n}⋃Si={2,3,

yo_bc的博客 671

hdu 6060 RXD and dividing

链接题意:有一颗n个节点的树,现在将节点2-n分成k组,定义每组的的权值为该组内所有点加编号为1的节点相互连接所经过的边的权值的和,求k组点集最大的和。分析:使用贪心的思想,我们思考每条边对最终答案的贡献。既然要结果最大,那么每条边就尽可能的多被走到。 如上图,现在考虑A-C这条边所做的贡献,很容易想到,在计算一个分组的权值时,如果C点或C的子节点有一个是属于该分组的 , 那么在计算该分组的权值

你的目光看海的博客 713

hdu 6060 RXD and dividing (贪心)

RXD has a tree TT, with the size of nn. Each edge has a cost.  Define f(S)f(S) as the the cost of the minimal Steiner Tree of the set SS on tree TT.  he wants to divide 2,3,4,5,6,…n2,3,4,5,6

黑码 460

HDU 6060 RXD and dividing

RXD and dividing Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 441    Accepted Submission(s): 179 Problem Description RXD has a

Mr__Kid的博客 1090

hdu6060斯坦纳树

hdu6060 题意:给出一颗n个节点的树,要求将2-n号节点分成k部分,然后再将每一部分加上1号节点联通的最小花费,定义为每一部分的val,为其在原图上的最小斯坦纳树,问总的val最大可能是多少。把1看成整棵树的根. 问题相当于把2∼n每个点一个[1,k]的标号. 然后根据最小斯坦纳树的定义(x,fa(x) ),(x,fa(​x)​​ ) 这条边的贡献是 x 子树内不同标号的个数目dif(​i)

猿的进化 642
上一篇: hdu 3954 Level up 线段树 升级版Lazy tag 区间整体的性质
下一篇: 2017多校联合第三场 1003题 hdu 6058 Kanade's sum 链表
kkkkahlua
博客等级 码龄12年 4粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值