zoukankan      html  css  js  c++  java
  • bzoj1706: [Usaco2007 Nov]relays 奶牛接力跑 (Floyd+新姿势)

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

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

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

        先把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
  • 相关阅读:
    异步非阻塞
    jdbc简单入门
    网络编程
    多线程
    java方法
    java之面向对象
    java-多线程
    Java之反射机制
    使用C#完成冒泡排序
    TextEdit不能空验证设置
  • 原文地址:https://www.cnblogs.com/Sakits/p/5572788.html
Copyright © 2011-2022 走看看