bzoj 1706 奶牛接力 矩阵乘法

题意:给出m条边、起点和终点,从起点开始恰好走过n条边(可以重复),求这n条边加起来的最小值。

分析:首先要知道这题最多只有100个点,然后把点离散化(点的坐标为1-1000)后建立邻接矩阵A。则A的某个点[i,j]表示从点i走一条边到底j的最小权值和。现在要走n条边,从一般的思路来看应该是求A^n然后再处理一下,但这题显然不能这么干。于是我们就把矩阵的乘法改变一下:原本是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])。然后最后输出c[s,e]就好啦。

代码:

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

var
  n,m,s,e,i,j,len,x,y,tot:longint;
  c,d:arr;
  num:array[1..1000] of longint;

procedure jia(a,b:arr);
var
  i,j,k:longint;
begin
  for i:=1 to tot do
    for j:=1 to tot do
      c[i,j]:=maxlongint div 3;
  for i:=1 to tot do
    for j:=1 to tot do
      for k:=1 to tot do
        if (a[i,k]<maxlongint)and(b[k,j]<maxlongint) then
          if a[i,k]+b[k,j]<c[i,j] then
            c[i,j]:=a[i,k]+b[k,j];
end;

procedure ksm(x:longint);
begin
  if x=1 then exit;
  ksm(x div 2);
  jia(c,c);
  if x mod 2=1 then jia(c,d);
end;

begin
  readln(n,m,s,e);
  for i:=1 to m 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;
  for i:=1 to tot do
    for j:=1 to tot do
      if d[i,j]=0 then d[i,j]:=maxlongint;
  c:=d;
  ksm(n);
  writeln(c[num[s],num[e]]);
end.


你可能感兴趣的:(bzoj 1706 奶牛接力 矩阵乘法)