ssl2510/bzoj 1706 奶牛接力 矩阵乘法

题目大意

给一个无向图,给定起点(s)和终点(e),要走过t条边(t给定)(可以重复走)。求从起点到终点经过t条边的最短路。

分析

  我们先从动态规划开始想,很容易就可以推出一条状态转移方程:

  F[I,j]=min(f[i-1,k]+g[k,j])(1<=k<=n) (1<=i<=t)

  其中,f[I,j]表示经过i条边到达点j的最短路径,N为顶点数,若点k,j间有边,G[k,j]为边权,否则为maxlongint。

  但是这个动态规划的时间复杂度是O(t*n*n),题目中t<=1,000,000,n<=100。所以会超时。

  所以我们要用矩阵乘法来做此题。建立一个邻接矩阵A,其中A[I,j]表示从i点到j点走一条边的最短路径。现在要走t条边,从一般的思路来看应该是求A^t然后再处理一下,但这题显然不能这么干(虽然我也不知道为什么是显然)。

  那能否修改矩阵乘法?能!

  可以从那一条状态转移方程找到灵感,把原本是c[i,j]=sum(a[i,k]*b[k,j]),现在改成c[i,j]=min(a[i,k]+b[k,j])且(0<a[i,k],0<b[k,j])。(具体为什么不想打字了,自己举例手算一下就知道了)。

  然后用新的矩阵乘法(矩阵加法)来求A^t,输出(a[s,e])即可。

  Ps:输入的点要离散。

type
  arr=array[1..110,1..110] of longint;

var
  a,c:arr;
  b:array[1..10000] of longint;
  tot:longint;
  i,j,k,l:longint;
  n,m,x,y:longint;

function cheng(x,x1:arr):arr;
var
  i,j,k:longint;
begin
  fillchar(cheng,sizeof(cheng),0);
  for i:=1 to tot do
    for j:=1 to tot do
      begin
        cheng[i,j]:=maxlongint div 3;
        for k:=1 to tot do
          if (x[i,k]<maxlongint) and (x1[k,j]<maxlongint)
            then
              if cheng[i,j]>x[i,k]+x1[k,j]
                then cheng[i,j]:=x[i,k]+x1[k,j];
      end;
end;

procedure seach(n:longint);
var
  i,j,k:longint;
begin
  if n=1 then exit;
  seach(n div 2);
  c:=cheng(c,c);
  if n mod 2=1 then c:=cheng(c,a);
end;

begin
  readln(n,m,x,y);
  fillchar(b,sizeof(b),0);
  for i:=1 to 110 do
    for j:=1 to 110 do
      a[i,j]:=maxlongint;
  for i:=1 to m do
    begin
      readln(l,j,k);
      if b[j]=0
        then
          begin
            tot:=tot+1;
            b[j]:=tot;
          end;
      if b[k]=0 then
        begin
          tot:=tot+1;
          b[k]:=tot;
        end;
      a[b[j],b[k]]:=l;
      a[b[k],b[j]]:=l;
    end;
  c:=a;
  seach(n);
  write(c[b[x],b[y]]);
end.


posted @ 2016-04-02 11:06  一个响亮的蒟蒻  阅读(109)  评论(0编辑  收藏  举报