zoukankan      html  css  js  c++  java
  • bzoj1297: [SCOI2009]迷路(矩阵乘法+拆点)

          题目大意:有向图里10个点,点与点之间距离不超过9,问从1刚好走过T距离到达n的方案数。

      当时看到这题就想到了某道奶牛题(戳我)。这两道题的区别就是奶牛题问的是走T条边,这道题是每条边都有一个边权求走过T边权的方案数。。。所以可以看成奶牛题相当于这一题里的边权为1的情况。

          首先边权为1就把奶牛题的floyd那段改成矩乘就可以了,那么接下来考虑边权不为1的情况,因为边权最多为9,我们就可以把每个点拆成9个点,x[1]~x[9]为x拆完的点,x[i]和x[i+1]连一条边权为1的边,然后x到y有一条边权为z的边,那么就把x的第z个点往y的第1个点连一条边,当然也可以把x[i]和x[i-1]连边然后把x的第一个点往y的第z个点连边,都是等价的,因为x跑到y第z个点再跑回y和x跑z个点再到y所走过的都是z个点。然后跑矩乘就可以辣。

    代码如下:

    type
      map=array[0..233,0..233]of longint;
    var
      n,m,t,i,j,x:longint;
      ch:char;
      mapp,a:map;
    
    function pos(i,j:longint):longint;
    begin
      exit((j-1)*m+i);
    end;
    
    procedure merge(var x,y:map);
    var
      i,j,k:longint;
      z:map;
    begin
      fillchar(z,sizeof(z),0);
      for i:=1 to n do
      for j:=1 to n do
      for k:=1 to n do
      z[i,j]:=(z[i,j]+x[i,k]*y[k,j])mod 2009;
      x:=z;
    end;
    
    procedure qp(y:longint);
    var
      x:map;
    begin
      x:=mapp;
      while y>0 do
      begin
        if y and 1=1 then merge(a,x);
        merge(x,x);
        y:=y>>1;
      end;
    end;
    
    begin
      readln(m,t);
      n:=m*9;
      for i:=1 to m do
      for j:=1 to 8 do
      mapp[pos(i,j),pos(i,j+1)]:=1;
      for i:=1 to m do
      begin
        for j:=1 to m do
        begin
          read(ch);x:=ord(ch)-ord('0');
          if x=0 then continue;
          mapp[pos(i,x),j]:=1;
        end;
        readln;
      end;
      for i:=1 to n do
      a[i,i]:=1;
      qp(t);
      writeln(a[1,m]);
    end.
    View Code
  • 相关阅读:
    淘宝技术架构演进之路
    单点登录
    [c++11] ——条件变量(Condition Variable)
    std::lock_guard unique_lock
    C++中push_back和emplace_back的区别
    C++11 CAS无锁函数compare_exchange_weak的使用
    C++11新特性之 rvalue Reference(右值引用)
    C++ auto和decltype的区别
    ovs contrack
    周总结03
  • 原文地址:https://www.cnblogs.com/Sakits/p/5989798.html
Copyright © 2011-2022 走看看