题意:
有n个兄弟去野餐,目的地为Park。每个人可以选择直接去Park,也可以选择去其他人家,和他一起坐车去Park。
每个人家的停车位没有限制,但是Park的停车数不能超过k。问所有人的最短路程。
思路:
假设Park的停车数没有限制,那么这题就是一道最小生成树了。
但是本题限制Park的停车数不能超过k,把Park看做根节点记为V0,那么就是说它的度数不能超过k。
得到一棵k度限制生成树的步骤:
1. 忽略根节点做一次kruskal,此时得到的是一个森林,包含了m个最小生成树。
2. 对于每一颗最小生成树树,选择其中离根节点最近的点,向根节点连一条边,此时得到了一棵m度的最小生成树。
3. 由m度生成树得到m+1度生成树:
(1). 用dp预处理出当前生成树中从V0到点i的路径上与V0无关联的权值最大的边,记为dp[i].d,该边的两端点记为dp[i].u和dp[i].v。
(2). 对于一个不在生成树中的边, 如果将该边加入生成树中,则一定会得到一个环。
此时我们删掉环中权值最大的边,即(1)中预处理得到的dp[v],得到一棵m+1度的生成树。
(3). 对于(2)枚举每一个v,记minnum=min{(V0, v) - dist[v].d },使minnum得到最小值的点v就是这次选择的点。连接V0, v,删去dp[v]。
4. 重复步骤3直到得到一棵k度限制生成树。本题要求度数不超过k,所以在某一步中,minnum>=0,就可以输出答案了。
关于minnum的含义:
minnum为在从m度生成树得到m+1度生成树的过程中,选择一个点v(连接V0, v,删去dp[v])可以得到的最大利益,即生成树的值最多可以减少多少。
minnum为负数,表示选择点v可以生成树的值减少,那么使minnum最小的点就是可以使生成树的值减少最多的点,这次我们便选择它。
如果minnum>=0,说明得到m+1度生成树不会获得任何利益,就不用继续下去,直接输出答案即可。
关于最小度数限制生成树详情参考2004国家集训队汪汀的论文。
代码(760K,47MS):
#include
#include
#include
#include
#include
#include