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.

时间: 2024-08-28 10:14:16

bzoj1297: [SCOI2009]迷路(矩阵乘法+拆点)的相关文章

BZOJ1297 SCOI2009 迷路 矩阵乘法

题意:给定一张有N个点的有向图,求0到N-1长度为T的路径的总条数. 题解:把长度为K的边拆成K条长度为1的边,然后建出邻接矩阵快速幂裸上. #include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namespace std; #define P(x

BZOJ 1297 SCOI2009 迷路 矩阵乘法

题目大意:给定一个邻接矩阵,求1~n的边权恰好为T的路径条数 考虑当所有边权都是1的时候 那么显然邻接矩阵自乘T次之后a[1][n]就是答案 因为当边权为1的时候a[i][j]可以表示从第i个点转移到第j个点的方案数 显然这个符合矩乘的定义 现在边权最大为9 那么将一个点拆成9个 第i个点拆成的第j+1个点向第j个点连一条边权为1的边 那么i->j有一条边权为k的边等价于i向j拆成的第k个点连边 #include <cstdio> #include <cstring> #in

bzoj1297 [SCOI2009]迷路——拆点+矩阵快速幂

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1297 一看感觉是矩阵快速幂之类的,但边权不好处理啊: 普通的矩阵快速幂只能处理边权为1的,所以想办法把边权处理成1: 仔细一看还有一个条件是边权小于10: 所以拆点!把一个点拆成10个点表示到它不同的距离,那么和它相连的那些点就可以跟某个距离的点连边权为1的边: 虽然没有自己想出来,不过1A还是极好的!(因为太简单了) 代码如下: #include<iostream> #include&

BZOJ1297 [SCOI2009]迷路 【矩阵优化dp】

题目 windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间. 输入格式 第一行包含两个整数,N T. 接下来有 N 行,每行一个长度为 N 的字符串. 第i行第j列为'0'表示从节点i到节点j没有边. 为'1'到'9'表示从节点i到节点j需要耗费的时间. 输出格式 包含一个整数,可能的路径数

BZOJ 1297: [SCOI2009]迷路 [矩阵快速幂]

Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间. Input 第一行包含两个整数,N T. 接下来有 N 行,每行一个长度为 N 的字符串. 第i行第j列为'0'表示从节点i到节点j没有边. 为'1'到'9'表示从节点i到节点j需要耗费的时间. Output 包

BZOJ1297 [SCOI2009]迷路

Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间. Input 第一行包含两个整数,N T. 接下来有 N 行,每行一个长度为 N 的字符串. 第i行第j列为'0'表示从节点i到节点j没有边. 为'1'到'9'表示从节点i到节点j需要耗费的时间. Output 包

矩阵乘法专题1——bzoj 1297 [SCOI2009] 迷路题解

题目链接 题意:给两个长度分别为n和m的序列,现在有两种操作:1.分别选择两个序列的一个非空前缀,切两个前缀的最后一位相同,删除之,得到1分(只累计),消耗e:2.直接删除两个序列,消耗值定于两个序列之前删除的元素个数之和,并且使得得到的分有效(之前没有有效分) 分析: 首先,问题其实就是转化成,进行若干次操作1,然后进行操作2 还要找到一个判别标准,来评判较优的状态(贪心) 每次的消耗值比较大,其实可以计算出最大的删除次数,这个值不是很大 状态表示: 简单的,一个状态可以表示为串A的位置.串B

B20J_1297_[SCOI2009]迷路_矩阵乘法

题意:有向图 N 个节点,从节点 0 出发,必须恰好在 T 时刻到达节点 N-1.总共有多少种不同的路径? 2 <= N <= 10 : 1 <= T <= 1000000000   边权范围[1,9]. 分析:首先看题目数据性质,N很小,即使是完全图边数也不会超过100.因此我们可以利用矩阵乘法优化. 如何优化:1.我们发现,当边权为1时每走一步就相当于乘上一次图的邻接矩阵.可以用矩阵快速幂O(N^3*logT)快速解决: 2.如果边权不为1我们可以运用拆点的技巧. 代码 值得注

bzoj1297 / P4159 [SCOI2009]迷路

P4159 [SCOI2009]迷路 如果边权只有 0/1 那么不就是一个灰常简单的矩阵快速幂吗! 然鹅边权 $<=9$ 所以我们把每个点拆成9个点! 解决~ 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define re register 5 using namespace std; 6 const int mod=2009; 7 int m,n,t;long long q; 8