APIO2010 巡逻

 

APIO2010 巡逻

【题目描述】

在一个地区中有 n个村庄,编号为1, 2, ..., n。有n – 1条道路连接着这些村庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其他任一个村庄。每条道路的长度均为 1个单位。
  为保证该地区的安全,巡警车每天要到所有的道路上巡逻。警察局设在编号为1的村庄里,每天巡警车总是从警察局出发,最终又回到警察局。
  下图表示一个有8个村庄的地区,其中村庄用圆表示(其中村庄 1用黑色的圆表示),道路是连接这些圆的线段。为了遍历所有的道路,巡警车需要走的距离为14 个单位,每条道路都需要经过两次。

为了减少总的巡逻距离,该地区准备在这些村庄之间建立 K 条新的道路,每条新道路可以连接任意两个村庄。两条新道路可以在同一个村庄会合或结束(见下面的图例(c) )。一条新道路甚至可以是一个环,即,其两端连接到同一个村庄。


  由于资金有限,K 只能是 1或2。同时,为了不浪费资金,每天巡警车必须经过新建的道路正好一次。
  下图给出了一些建立新道路的例子:

在(a)中,新建了一条道路,总的距离是 11。在(b)中,新建了两条道路,总的巡逻距离是 10。在(c)中,新建了两条道路,但由于巡警车要经过每条新道路正好一次,总的距离变为了 15。
  试编写一个程序,读取村庄间道路的信息和需要新建的道路数,计算出最佳的新建道路的方案使得总的巡逻距离最小,并输出这个最小的巡逻距离。 

【输入文件】

第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b,
表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。

【输出文件】

输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。

【输入样例】

8 1 

1 2 

3 1 

3 4 

5 3 

7 5 

8 5 

5 6 

【输出样例】

11

【数据范围】


10%的数据中,n ≤ 1000,  K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。 

【题目分析】

K=1的情况比较简单,求出树的直径,把直径两端连上就行了。

K=2的时候,还要练一条边,这时候,我们讨论3种情况:

1、所连的两个端点在直径上某一个点的不同非直径子树上

2、所连的两个端点在直径上某两个点的非直径子树上

3、所连的两个端点在直径上某一个点的相同非直径子树上

首先对于情况一,可以对直径上每个点进行一次dfs求得不重合的最长链与次长链解决。

对于情况三,也可以在dfs的过程中解决,我们主要讨论一下情况二。

把直径作为一条长度为tot的链,用max[i]表示第i个点可以扩展的非直径最长链,那么我们的目的是求max[j]+max[i]-(j-i)的最大值,其中j>i。

将上式转化,可化为max[i]+i+max[j]-j,那么对于每一个枚举的i,max[i]+i为定值,而对于j=i+1..n中max[j]-j的最大值也可以由预处理得到,这样就得出了结果。

最后的答案在这三种情况中取一个min就行了。

【代码实现】

 

Code
  1 program test2;
  2 type bian=record
  3       y,next:longint;
  4      end;
  5 var a:array[0..200000]of bian;
  6     d,b,zj,pre,g,len,q:array[0..100000]of longint;
  7     v:array[0..100000]of boolean;
  8     i,j,m,n,ans1,ans2,m1,m2,tot,x,y,k,tmp:longint;
  9 procedure bfs(s:longint);
 10 var t,w,i,j,x:longint;
 11 begin
 12     fillchar(v,sizeof(v),0);
 13     t:=1;w:=1;d[1]:=s;v[s]:=true;b[s]:=0;
 14     while t<=w do
 15     begin
 16         x:=d[t];inc(t);
 17         i:=g[x];
 18         while i<>0 do
 19         begin
 20             if not v[a[i].y] then
 21             begin
 22                 pre[a[i].y]:=x;
 23                 b[a[i].y]:=b[x]+1;
 24                 inc(w);
 25                 d[w]:=a[i].y;
 26                 v[a[i].y]:=true;
 27             end;
 28             i:=a[i].next;
 29         end;
 30     end;
 31 end;
 32 function dfs(i:longint):longint;
 33 var tmp,tt,j,m1,m2:longint;
 34 begin
 35     tmp:=-1;
 36     m1:=0;m2:=0;
 37     j:=g[i];
 38     while j<>0 do
 39     begin
 40         if not v[a[j].y] then
 41         begin
 42             v[a[j].y]:=true;
 43             tt:=dfs(a[j].y);
 44             if tt>tmp then tmp:=tt;
 45             if tt+1>m1 then
 46             begin
 47                 m2:=m1;
 48                 m1:=tt+1;
 49             end
 50             else if tt+1>m2 then m2:=tt+1;
 51         end;
 52         j:=a[j].next;
 53     end;
 54     if ans1-m1-m2+1<ans2 then ans2:=ans1-m1-m2+1;
 55     exit(tmp+1);
 56 end;
 57 procedure insert(x,y:longint);
 58 begin
 59     inc(tot);
 60     a[tot].y:=y;
 61     a[tot].next:=g[x];
 62     g[x]:=tot;
 63 end;
 64 function max(a,b:longint):longint;
 65 begin
 66     if a>b then exit(a)
 67     else exit(b);
 68 end;
 69 begin
 70     readln(n,m);
 71     for i:=1 to n-1 do
 72     begin
 73         readln(x,y);
 74         insert(x,y);
 75         insert(y,x);
 76     end;
 77     bfs(1);
 78     j:=1;
 79     for i:=1 to n do
 80       if b[i]>b[j] then j:=i;
 81     bfs(j);
 82     k:=j;
 83     for i:=1 to n do
 84       if b[i]>b[k] then k:=i;
 85     ans1:=2*n-2-b[k]+1;
 86     if m=1 then
 87     begin
 88         writeln(ans1);
 89         close(input);close(output);
 90         halt;
 91     end;
 92     tot:=1;zj[tot]:=k;
 93     fillchar(v,sizeof(v),0);
 94     v[k]:=true;
 95     while k<>j do
 96     begin
 97         k:=pre[k];
 98         inc(tot);
 99         zj[tot]:=k;
100         v[k]:=true;
101     end;
102     ans2:=maxlongint;
103     for i:=1 to tot do
104     begin
105         m1:=0;m2:=0;
106         b[zj[i]]:=0;
107         j:=g[zj[i]];
108         while j<>0 do
109         begin
110             if not v[a[j].y] then
111             begin
112                 v[a[j].y]:=true;
113                 tmp:=dfs(a[j].y)+1;
114                 if tmp>m1 then
115                 begin
116                     m2:=m1;
117                     m1:=tmp;
118                 end
119                 else if tmp>m2 then m2:=tmp;
120             end;
121             j:=a[j].next;
122         end;
123         len[i]:=m1;
124         if ans1-m1-m2+1<ans2 then
125           ans2:=ans1-m1-m2+1;
126     end;
127     q[tot]:=len[tot]-tot;
128     for i:=tot-1 downto 1 do
129       q[i]:=max(q[i+1],len[i]-i);
130     for i:=1 to tot-1 do
131     begin
132         tmp:=q[i+1]+len[i]+i;
133         if ans1-tmp+1<ans2 then ans2:=ans1-tmp+1;
134     end;
135     writeln(ans2);
136 end.

转载于:https://www.cnblogs.com/whitecloth/archive/2012/05/05/2484855.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值