这道题代码实在是太长了,而标程又是错的,写起来一定会耗不少时间,因此这里就不写代码了,就说下思路吧。
第一次看到这题,想到了NOIP2007树网的核那道题,只是那道题与这道题相比实在是小巫见大巫了……首先枚举的不是最长路,点的范围是0~10000不允许枚举,其它的地方与07年那道题基本无异,我甚至怀疑07年那道题是不是这道题的简化版?
不瞎扯了,先说一下O(n2)的思路:
很简单,就是枚举起点和终点,然后各个不属于路径上的点都要找一个到路径上的点的距离的最小值,把最小值进行累加即可得出结果。
下面重点将O(n)的思路:
O(n)的思路就是很好的用到了树的相关知识,因为题中给出了网关这个概念,所以应该很好想到用树。
首先定义三种变量:
i.downsum 表示以i为根的子结点到i点的距离
i.allsum 表示所有点到i的距离
i.ge 表示以i为根的子结点的个数
再定义:
f[i] 表示以i为起点的向下的一条路径的权值和
如果i选择了它的子结点j与k的话,那么新的延迟总和:
{f[j]-(j.allsum-j.downsum)}+{f[k]-(k.allsum-k.downsum)}+{i.allsum-(j.downsum+j.ge*w(i,j)-(k.downsum+k.ge*w(i,k))}
这里详细解释一下:
第一个{}里表示以结点j为根的子树上的所有结点到新路径的距离总和
第二个{}里表示以结点k为根的子树上的所有结点到新路径的距离总和
第三个{}里表示其余结点(既不属于j的子结点也不属于k的子结点)的所有结点到新路径的距离总和
上面的式子经过化简之后可以得到:
延迟总和=i.allsum-{[j.downsum+j.ge*w(i,j)]-[k.downsum+k.ge*w(i,k)]-[f[j]-(j.allsum-j.downsum)]-[f[k]-(k.allsum-k.downsum)]}
显然i的取值至于j和k的取值有关,因此我们只需找一个最大的j和k来满足i的值最小。
再看看我们定义的那三种变量,其中i.downsum和i.ge因为只与子结点有关,因此通过递归可以得出结果,但是i.allsum就不行,但是我们可以换种思路,用自上向下的方法求出i.allsum。
有一些式子是显然成立的:
root.allsum=root.downsum
i.allsum=father[i].allsum-i.ge*w(father[i],i)+(n-i.ge)*w(father[i],i)
总而言之,认真的思考与大胆的猜想才是解决DP题目的关键。同时对于明显的给出树的问题,例如有明显的子结点与父结点之间的联系的,一定要想到树,这样的话父结点与子结点是很容易建立关系的。
第一次看到这题,想到了NOIP2007树网的核那道题,只是那道题与这道题相比实在是小巫见大巫了……首先枚举的不是最长路,点的范围是0~10000不允许枚举,其它的地方与07年那道题基本无异,我甚至怀疑07年那道题是不是这道题的简化版?
不瞎扯了,先说一下O(n2)的思路:
很简单,就是枚举起点和终点,然后各个不属于路径上的点都要找一个到路径上的点的距离的最小值,把最小值进行累加即可得出结果。
下面重点将O(n)的思路:
O(n)的思路就是很好的用到了树的相关知识,因为题中给出了网关这个概念,所以应该很好想到用树。
首先定义三种变量:
i.downsum 表示以i为根的子结点到i点的距离
i.allsum 表示所有点到i的距离
i.ge 表示以i为根的子结点的个数
再定义:
f[i] 表示以i为起点的向下的一条路径的权值和
如果i选择了它的子结点j与k的话,那么新的延迟总和:
{f[j]-(j.allsum-j.downsum)}+{f[k]-(k.allsum-k.downsum)}+{i.allsum-(j.downsum+j.ge*w(i,j)-(k.downsum+k.ge*w(i,k))}
这里详细解释一下:
第一个{}里表示以结点j为根的子树上的所有结点到新路径的距离总和
第二个{}里表示以结点k为根的子树上的所有结点到新路径的距离总和
第三个{}里表示其余结点(既不属于j的子结点也不属于k的子结点)的所有结点到新路径的距离总和
上面的式子经过化简之后可以得到:
延迟总和=i.allsum-{[j.downsum+j.ge*w(i,j)]-[k.downsum+k.ge*w(i,k)]-[f[j]-(j.allsum-j.downsum)]-[f[k]-(k.allsum-k.downsum)]}
显然i的取值至于j和k的取值有关,因此我们只需找一个最大的j和k来满足i的值最小。
再看看我们定义的那三种变量,其中i.downsum和i.ge因为只与子结点有关,因此通过递归可以得出结果,但是i.allsum就不行,但是我们可以换种思路,用自上向下的方法求出i.allsum。
有一些式子是显然成立的:
root.allsum=root.downsum
i.allsum=father[i].allsum-i.ge*w(father[i],i)+(n-i.ge)*w(father[i],i)
总而言之,认真的思考与大胆的猜想才是解决DP题目的关键。同时对于明显的给出树的问题,例如有明显的子结点与父结点之间的联系的,一定要想到树,这样的话父结点与子结点是很容易建立关系的。