poj3613 奇特的矩阵乘法

  


       题目大意很简单:给出一个无向图,求两个点之间的经过k条边的最短路(边可以重复经过)

      最多只有100条边,但是k高达10^6。


      可以用 类bellman ford的方法,将边迭代n次

       (与bellman ford不同的是,每一次迭代都必须选边,不过spfa无法保证每一条边都取);

      这样的复杂的事o(ne)的 ,已经有10^8,而且中间还涉及大量的数组滚动,要ac还是太难了。


     于是,一种奇异的算法出现了——矩阵乘法;

     如果我们用邻接矩阵存好走k条边的距离之后,与贮存了边的邻接矩阵相称,得到的矩阵就是走k+1条边的距离,

     只要把这里的矩阵相乘的方式改为——a[ i , j ]:=min(b [ i,k]+b [ k , j ]),即乘法改为加法,加法改为取min

      由于加法和min满足结合率,可以直接快速幂了,复杂度是100^3 * log(10^6).

    

     

   

program lmd;
var
    i,j,k,n,maxn,x,y,z,t,s,e:longint;
    mul,now,ans:array[1..1000,1..1000]of longint;
    hash:array[1..1000]of longint;
    yes:array[1..1000]of boolean;
    a:array[0..100+5]of record
                 x,y,z:longint;
                 end;
begin
    assign(input,'3613.in');
    assign(output,'3613.out');
    reset(input);rewrite(output);
     read(n,t,s,e);
     fillchar(yes,sizeof(yes),false);
     maxn:=0;
     for i:=1 to t do
      begin
        read(a[i].z,a[i].x,a[i].y);
        yes[a[i].x]:=true;
        yes[a[i].y]:=true;
      end;
     maxn:=0;
     for i:=1 to 1000 do
       if yes[i] then
         begin
           inc(maxn);
           hash[i]:= maxn;
         end;
     for i:=1 to maxn do
      for j:=1 to maxn do
        begin
         mul[i,j]:=maxlongint shr 1;
         ans[i,j]:=maxlongint shr 1;
        end;
     for i:=1 to t do
       begin
          mul[hash[a[i].x],hash[a[i].y]]:=a[i].z;
          mul[hash[a[i].y],hash[a[i].x]]:=a[i].z;
       end;
     for i:=1 to maxn do
       ans[i,i]:=0;
     while n>0 do
      begin
         if n and 1=1 then
          begin
           for i:=1 to maxn do
             for j:=1 to maxn do
              begin
               now[i,j]:=ans[i,j];
               ans[i,j]:=maxlongint shr 1;
              end;
           for i:=1 to maxn do
             for j:=1 to maxn do
               for k:=1 to maxn do
                 if ans[i,j]>now[i,k]+mul[k,j] then
                     ans[i,j]:=now[i,k]+mul[k,j];

           end;
         for i:=1 to maxn do
            for j:=1 to maxn do
              now[i,j]:=maxlongint shr 1;
         for i:=1 to maxn do
           for j:=1 to maxn do
             for k:=1 to maxn do
             if now[i,j]>mul[i,k]+mul[k,j] then
                now[i,j]:=mul[i,k]+mul[k,j];
         for i:=1 to maxn do
          for j:=1 to maxn do
             mul[i,j]:=now[i,j];

         n:=n shr 1;
      end;
    write(ans[hash[s],hash[e]]);
    close(input);close(output);
end.                        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值