noip2007树网的核题解

    废话不说,直接进入正题。在这里本题将介绍四种方法。

    算法一:在树中,最短路等于最长路,因此我们可以用floyd算法求每两点间的距离,并找出直径。然后枚举直径上的核,模拟得出偏心距。这样的算法时间复杂度是O(n^3)。在这里有一个性质,对于每条直径都有核,而最小偏心距是唯一的,所以我们只要枚举其中一条直径就可以了,证明就略啦。

    且对于直径上的一条路径F,它的偏心距是可以在O(1)的时间内求出来的。

       ecc:=max{min{dist[st,i],dist[st,j]},min{dist[ed,i],dist[ed,j]}};

     其中st、ed为直径两端,i、j为线段两端。证明如下:我们假设存在非直径端点的一点k,如果dis[k,i]<dis[i,st]那么st为最远距离,如果dis[k,i]>dis[i,st]那么当前的直径就不是最长的路径,就和它是直径相矛盾,所以我们对于一条直径上的路径可以得到如上计算偏心距的方法。

     这里贴一下代码吧。

View Code
 1 var i,j,n,m,k,l,x,y,z,ans:longint;
2 f,a:array[0..300,0..300]of longint;
3 b:array[0..300]of longint;
4 function max(a,b:longint):longint;
5 begin
6 if a>b then exit(a) else exit(b);
7 end;
8 function min(a,b:longint):longint;
9 begin
10 if a<b then exit(a) else exit(b);
11 end;
12 begin
13 assign(input,'core.in');reset(input);
14 assign(output,'core.out');rewrite(output);
15 readln(n,m);
16 fillchar(f,sizeof(f),63);
17 for i:=1 to n do f[i,i]:=0;
18 for i:=1 to n-1 do
19 begin
20 read(x,y,z);
21 f[x,y]:=z;
22 f[y,x]:=z;
23 end;
24 for k:=1 to n do
25 for i:=1 to n do
26 for j:=1 to n do
27 if (f[i,j]>f[i,k]+f[k,j]) then
28 begin
29 f[i,j]:=f[i,k]+f[k,j];
30 end;
31 k:=0;
32 for i:=1 to n do
33 for j:=1 to n do
34 if f[i,j]>k then
35 begin
36 k:=f[i,j];
37 x:=i;y:=j;
38 end;
39 l:=0;
40 for i:=1 to n do
41 if f[x,i]+f[i,y]=f[x,y] then
42 begin
43 inc(l);
44 b[l]:=i;
45 end;
46 ans:=maxlongint;
47 for i:=1 to l do
48 for j:=1 to l do
49 begin
50 if f[b[i],b[j]]>m then continue;
51 k:=max(min(f[x,b[i]],f[x,b[j]]),min(f[b[i],y],f[b[j],y]));
52 if k<ans then ans:=k;
53 end;
54 writeln(ans);
55 close(input);close(output);
56 end.

    算法二:树形动态规划。 算法首先要求我们找出一条路径(这可以通过著名的“两次BFS”算法得到),然后,选取任意一个在直径上的点作为根节点建立有根树,通过经典树形动态规划确定节点的最长下降路和次长下降路。
    然后,算法枚举路径的起点。然后基于下述事实:合法路径只能向最长下降路方向延伸。(如果不是这样,则最长下降路不能被屏蔽,其偏心矩一定不会是最小;另外,合法路径不能像两条路上延伸,因为我们枚举的是路径的起点)。通过这个事实,很容易进行一个简单的树形动态规划在O(n)的时间内对于每一个确定的起点给出这种情形下的最小偏心矩。
   该算法的时间复杂度为O(n2),且简洁明了,是本题的正统算法。

   从此开始的算法,参考了各种资料,忘勿介意,笔者只是加以整理归纳。

    算法三:贪心性质+二分答案。 如果我们已经知道了最小偏心矩,同时也知道指定的有根树中根必然在核上,则我们可以对每一个节点作一次从下到上的遍历,一旦长度超过给出的最小偏心矩,就将接下来的节点进行标记。(当然,这个过程直接进行的复杂度是O(n2)的,但是借鉴算法二中的动态规划,我们可以很轻松地通过自上而下的规划把复杂度降到O(n))。然后,我们观察被标记的节点(这些节点必须在核上)是否能够形成一条满足题意的核。
    要形成满足题意的核,必须满足这样几个条件:
   1、     必须形成一条路径,不能有分支。
   2、     必须向最长下降路或者是在直径上的次长下降路进行延伸。
   3、     路径的长度不能超过s.
  以上的3点判断都能在O(n)的动态规划中予以验证。故本题可以在O(n)的时间内完成对某一个已知最小偏心矩的判断。
  鉴于最小偏心矩的可行性是单调的,我们采用二分答案的方法可以解决本题,算法得时间复杂度为O(nlogc),其中c是给定    的图中直径的长度。从本题来看,c <= 300,000

    算法四:单调队列。

     我们先看一个性质。对于图中的每一条直径,都存在一段满足题意的核。题目说过了,直径与直径之间必然交于固定的一点。因此证明我们可以这么想,假设有两条直径,型如“>——<”,如果核在两条直径的重合部分上显然成立。当不在时,首先直径重合的部分的一侧的两条链是对称的(否则可以找到比直径长的路径,矛盾),如果核在<上,那其偏心距肯定在>--上。这么看来的话肯定不如核在中间部分优。

    言归正传,首先还是通过“两次BFS”给出图中的直径长度以及一条具体的直径。然后,对于该条直径而言,对于上面的路径的偏心距,可以用前面讲过的方法求,与算法一的差别就在于这里我们使用单调队列来维护这个最小的偏心距。整个算法的复杂度为O(n),是本题的最好算法。

posted @ 2011-10-24 20:18  N_C_Derek  阅读(525)  评论(0编辑  收藏  举报