码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1706: [Usaco2007 Nov]relays 奶牛接力跑 (Floyd+新姿势)

时间:2016-06-09 22:11:56      阅读:354      评论:0      收藏:0      [点我收藏+]

标签:

    题目大意:有t(t<=100)条无向边连接两点,求s到e刚好经过n(n<=10^7)条路径的最小距离。

    第一反应分层图,但是一看n就懵逼了,不会写。看了题解之后才知道可以这么玩。。。

    首先有100条边最多200个点,但点编号到1000,所以离散化一下。

    任何一个正整数都能用2的幂相加得到,所以先把n转变成2进制来看,按位考虑。dist[i][j][k]表示刚好经过2^i条边从j到k的最短距离,则dist[i,j,k]=min{dist[i-1][j][l]+dist[i-1][l][k]}。用类似快速幂的方法,若是2进制的n这一位是1的话,就把答案数组g和dist跑floyd(min{g[i-1][j][l]+dist[i-1][l][k]}),否则dist自己和自己跑(min{dist[i-1][j][l]+dist[i-1][l][k]}),这样子g就是跑n条路径得出的最小距离了

代码如下:

技术分享
type
  map=array[1..1000,1..1000]of longint;
var
  n,t,s,e,i,j,k,len,x,y,tot:longint;
  c,d,g:array[1..1000,1..1000]of longint;
  num:array[1..1000]of longint;

procedure merge(var a,b:map);
var
  i,j,k:longint;
begin
  fillchar(c,sizeof(c),63);
  for k:=1 to tot do
  for i:=1 to tot do
  for j:=1 to tot do
  if c[i,j]>a[i,k]+b[k,j] then
  c[i,j]:=a[i,k]+b[k,j];
  a:=c;
end;

procedure work;
begin
  fillchar(g,sizeof(g),63);
  for i:=1 to tot do g[i,i]:=0;
  while n>0 do
  begin
    if n and 1=1 then merge(g,d);
    merge(d,d);
    n:=n>>1;
  end;
  writeln(g[num[s],num[e]]);
end;

begin
  readln(n,t,s,e);
  fillchar(d,sizeof(d),63);
  for i:=1 to t do
  begin
    readln(len,x,y);
    if num[x]=0 then
    begin
      inc(tot);num[x]:=tot;
    end;
    if num[y]=0 then
    begin
      inc(tot);num[y]:=tot;
    end;
    d[num[x],num[y]]:=len;d[num[y],num[x]]:=len;
  end;
  work;
end.
View Code

 

bzoj1706: [Usaco2007 Nov]relays 奶牛接力跑 (Floyd+新姿势)

标签:

原文地址:http://www.cnblogs.com/Sakits/p/5572788.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!