Travel 纪中1782 分层图+spfa

Description

  给出一个有 个顶点 条边的有向图,对于一条边长度为len的边有两种走法。
  1、如果a和b可以互达,则走过这条边的时间为len
  2、如果a和b不可以互达,则走过这条边的时间为2*len
  现在给出一个k,问,从顶点1到顶点n,满足第二种走法不超过k次的最短时间是多少。

Input

  第一行有3个整数n,m,k(1<=n<=100,1<=m<=10000,0<=k<=10),表示有n个顶点,m条边。
  接下来有m行,每行有3个整数xi,yi,leni(1<=xi,yi<=n,1<=leni<=10000),表示长度为leni的有向边。
  注意,两个点可能有多条边连接。

Output

  一行一个整数,表示最短时间。
  如果没有满足题目条件的路径,则输出-1

分析

这又是一个分层图。
先用floyd处理出两个点是否互达。把不互达的两点之间的边处理一下。
设f[i,j]表示到达i点用了j次第二种走法的最短路。
如果连接x,y的一条边(边权为w)是第一种边,那它更新的是f[y,j]=f[x,j]+w
如果连接x,y的一条边(边权为w)是第二种边,那它更新的是f[y,j+1]=f[x,j]+w*2

代码

const
  maxn=110;
  maxe=12000;

type
  arr=record
    x,y:longint;
    w:longint;
    show:boolean;
    next:longint;
end;

var
  n,m,nm,num:longint;
  s,t:longint;
  edge:array[0..maxe] of arr;
  ls:array[0..maxn] of longint;
  f:array[0..maxn,0..100] of longint;
  g:array[0..maxn,0..maxn] of boolean;
  queue:array[0..4000000,1..2] of longint;
  status:array[0..maxn,0..100] of longint;

procedure add(x,y,w:longint);
begin
  num:=num+1;
  edge[num].x:=x;
  edge[num].y:=y;
  edge[num].w:=w;
  edge[num].next:=ls[x];
  edge[num].show:=false;
  ls[x]:=num;
end;

procedure init;
var
  i:longint;
  x,y,w:longint;
begin
  readln(n,m,nm);
  num:=0;
  fillchar(g,sizeof(g),0);
  for i:=1 to m do
    begin
      readln(x,y,w);
      g[x,y]:=true;
      add(x,y,w);
    end;
  s:=1; t:=n;
end;

procedure floyd;
var
  i,j,k:longint;
begin
  for k:=1 to n do
    for i:=1 to n do
      for j:=1 to n do
        if (i<>j) and (j<>k) and (i<>k) then
          g[i,j]:=(g[i,k] and g[k,j]) or g[i,j];
end;

procedure spfa;
var
  i,j,k:longint;
  head,tail:longint;
begin
  fillchar(f,sizeof(f),$7f);
  head:=0; tail:=1;
  queue[1][1]:=s;
  queue[1][2]:=0;
  f[s][0]:=0;
  status[s][0]:=1;
  repeat
    head:=head+1;
    i:=ls[queue[head][1]];
    while i<>0 do
      begin
        with edge[i] do
          begin
            j:=queue[head][2];
            if not show then
              if f[x,j]+wthen
                  begin
                    f[y,j]:=f[x,j]+w;
                    if status[y][j]=0
                      then
                        begin
                          tail:=tail+1;
                          queue[tail][1]:=y;
                          queue[tail][2]:=j;
                          status[y][j]:=1;
                        end;
                  end;
            if show then
              if jthen
                if f[x,j]+w1]
                  then
                    begin
                      f[y,j+1]:=f[x,j]+w;
                      if status[y][j+1]=0
                        then
                          begin
                            tail:=tail+1;
                            queue[tail][1]:=y;
                            queue[tail][2]:=j+1;
                            status[y][j+1]:=1;
                          end;
                    end;
            i:=next;
          end;
      end;
    status[queue[head][1]][queue[head][2]]:=0;
  until head=tail;
end;

procedure main;
var
  i,j,k:longint;
  ans:longint;
begin
  floyd;
  for i:=1 to n do
    begin
      j:=ls[i];
      while j<>0 do
        with edge[j] do
          begin
            if not g[x,y] or not g[y,x]
              then
                begin
                  edge[j].show:=true;
                  edge[j].w:=edge[j].w*2;
                end;
            j:=next;
          end;
    end;
  spfa;
  ans:=maxlongint;
  for i:=0 to nm do
    begin
      if ans>f[t,i] then ans:=f[t,i];
    end;
  if ans=2139062143
    then write(-1)
    else writeln(ans);
end;

begin
  init;
  main;
end.

你可能感兴趣的:(动态规划)