【原题】【noip2007 T4】树网的核(图论,最短路)

问题

描述 Description

【问题描述】
设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V, E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a,b)表示以a,b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a,b)为a,b两结点间的距离。
一点v到一条路径P的距离为该点与P上的最近的结点的距离:
  d(v,P)=min{d(v,u),u为路径P上的结点}。
树网的直径:树网中最长的路径称为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离, 即
   ECC(F)=max{d(v,F),v∈V}.
任务:对于给定的树网T=(V, E,W)和非负整数s,求一个路径F,它是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我们称这个路径为树网T=(V,E,W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。
::点击图片在新窗口中打开::

输入格式 Input Format

输入文件包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号依次为1, 2, ..., n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
所给的数据都是正确的,不必检验。

 

5 2
1 2 5
2 3 2
2 4 4
2 5 3

 

5

分析

最简单的方法——枚举。枚举每条直径,枚举直径上的每个路径,计算偏心率。

对于路径的长度,我们可以用spfa进行预处理,时间复杂度接近n2

对于偏心距我们可以得到如下的计算方法

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]那么当前的直径就不是最长的路径,就和它是直径相矛盾,所以我们对于一条直径上的路径可以得到如上计算偏心距的方法

插一副图帮助理解

clip_image001

反思

noip考察图论不会离开最短路,都是经典算法,比如最优贸易,关键是如何根据题意改造经典算法。贪心是不错的选择,经典算法可以做预处理,可以多次使用。在考虑时一定要尽量发挥经典算法的作用

code

program liukee;
var
  dis,map:array[0..300,0..300] of longint;
  a:array[0..300,0..300] of longint;
  v:array[0..300] of boolean;
  q:array[0..1000000] of longint;
  n,s,i,j,ed,st,ans,len,ecc:longint;

function max(a,b:longint):longint;
begin
  if a>b then exit(a);
  exit(b);
end;

function min(a,b:longint):longint;
begin
  if a<b then exit(a);
  exit(b);
end;

procedure init;
var
  i,x,y,z:longint;
begin
  readln(n,s);
  for i:=1 to n-1 do
  begin
    read(x,y,z);
	map[x,y]:=z;
	map[y,x]:=z;
	inc(a[x,0]);
	a[x,a[x,0]]:=y;
	inc(a[y,0]);
	a[y,a[y,0]]:=x;
  end;
end;

procedure spfa(s:longint);//求最短路
var
  i,l,r,now:longint;
begin
  for i:=1 to n do
    dis[s,i]:=maxlongint>>1;
  fillchar(v,sizeof(v),0);
  fillchar(q,sizeof(q),0);
  dis[s,s]:=0;
  v[s]:=true;
  q[1]:=s;
  l:=0;r:=1;
  while l<=r do
  begin
    inc(l);
	now:=q[l];
	for i:=1 to a[now,0] do
	  if dis[s,a[now,i]]>dis[s,now]+map[now,a[now,i]] then
	  begin
	    dis[s,a[now,i]]:=dis[s,now]+map[now,a[now,i]];
		if not v[a[now,i]] then
		begin
		  inc(r);
		  q[r]:=a[now,i];
		  v[a[now,i]]:=true;
		end;
	  end;
          v[now]:=false;
  end;
end;

begin
  init;
  for i:=1 to n do
    spfa(i);
  len:=-maxlongint;//寻找直径长度
  for i:=1 to n do
    for j:=1 to n do
	  if dis[i,j]>len then
	    len:=dis[i,j];
  ans:=maxlongint;
  for st:=1 to n-1 do//枚举起点
    for ed:=st+1 to n do//枚举直径终点
      if dis[st,ed]=len then//找到的是直径
        for i:=1 to n do//枚举路径
		  if dis[st,i]+dis[i,ed]=len then
		  for j:=1 to n do
		    if(dis[st,j]+dis[j,ed]=len)and(dis[i,j]<=s) then
			begin
  			  ecc:=max(min(dis[i,st],dis[j,st]),min(dis[i,ed],dis[j,ed]));//计算ecc
			  if ecc<ans then ans:=ecc;
			end;
  writeln(ans);
end.
		

 

 

转载于:https://www.cnblogs.com/liukeke/archive/2010/11/11/1875105.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值