C++解题报告:迷路[SCOI2009]——巧妙运用加速矩阵快速求解

news/2024/7/15 17:27:12 标签: 数论, 图论, 矩阵, 拆点

引言

好题一道,恶心到爆。。。


迷路

题目描述

windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

输入输出格式

输入格式:

 

第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。

 

输出格式:

 

包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

 

输入输出样例

输入样例#1: 复制

2 2
11
00

输出样例#1: 复制

1

输入样例#2: 复制

5 30
12045
07105
47805
12024
12345

输出样例#2: 复制

852

说明

【样例解释一】

0->0->1

【数据范围】

30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。

100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。


思路详解

看到这一道题和他的数据就会发现,这是一道好题。

先对样例来一波分析,有两个点,1 和 2 

图片

其邻接矩阵\begin{matrix} & \\ 1 \, 1 & \\0\, 0 \end{matrix},其中点1自身有自环,那么让这个矩阵自乘会怎样呢?矩阵自乘后为\begin{matrix} & \\1\, 1 & \\0\, 0 \end{matrix}没有用换一种想法

T=1, 点1 到 点1 有一种方法,点1 到 点2 有一种方法,有点牵强

换一组数据 n = 3 ,T = 2 ,邻接矩阵\begin{matrix} 0 & 1 & 1\\ 1 & 0 & 1\\ 1& 1 & 1 \end{matrix}(点3 有自环)

自乘一遍后得\begin{matrix} 2 & 1 & 2\\ 1 & 2 & 2\\ 2& 2 & 3 \end{matrix}

点1 到 点2 ,再回到点1;点1 到 点3 ,再回到点1,有 2 种方法

而由点1 到点2 只有点1——点3——点2 一种方法

有点1 到 点3 则有 2 种方法(剩下的自己可以去推一推)

那么得到的结论就是这个矩阵的T幂次方后的矩阵的第 i 行 j 列元素表示 i 到 j 的方法总数(有点绕)

但这个图(初始矩阵)的边权为 1 ,如果为其他的数呢?

这个就要对图进行拆点拆点详解),再对拆点后的图(矩阵)进行幂次方,这道题就解决了


代码

理解。。。消化。。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
  
int N , M , maxl ;
char a[107][107] ;
struct squr{
    int n , m ; 
    int b[107][107] ;
    squr() {
        memset( b , 0 , sizeof(b) ); 
    }
    squr operator * ( squr x ) {
        squr z ;
        z.n = n ;
        z.m = x.m ;
        for(int i = 1 ; i <= n ; ++ i ) 
            for(int j = 1 ; j <= z.m ; ++ j )
                for(int k = 1 ; k <= m ; ++ k )
                    z.b[i][j] = ( z.b[i][j] + b[i][k]*x.b[k][j] % 2009 ) % 2009;
        return z ;
    } //矩阵乘法 
};
  
int rep( int x , int y ) {
    return maxl*(x-1) + y ;
}
  
squr quick_pow( squr x , int y )//矩阵快速幂 
{
    squr sum ;
    sum.m = sum.n = N ;
    for(int i = 1 ; i <= sum.n ; ++ i ) sum.b[i][i] = 1 ;
    while( y > 0 ) {
        if( y %2 == 1 )
            sum = sum * x ;
        x = x *x ;
        y /= 2 ;
    }
    return sum ;
}
  
int main()
{
    squr B ;
    scanf("%d%d", &N , &M );
    for(int i = 1 ; i <= N ; ++ i ) {
        scanf("\n");
        for(int j = 1 ; j <= N ; ++ j ) {
            scanf("%c", &a[i][j] );
            maxl = max( maxl , a[i][j]-'0' );
        }
    }
    for(int i = 1 ; i <= N ; ++ i ) {
        for(int j = 1 ; j < maxl ; ++ j )
            B.b[ rep( i,j ) ][ rep( i,j+1 ) ] = 1 ;
        for(int j = 1 ; j <= N ; ++ j ) {
            if( a[i][j]-'0' != 0 )
                B.b[ rep( i,a[i][j]-'0' )][ rep( j,1 )] = 1 ;
        }
    }//拆点 
    N *= maxl;
    B.m = B.n = N ;
    B = quick_pow( B , M );
    printf("%d", B.b[1][N - maxl + 1] );
    return 0;
}

 


http://www.niftyadmin.cn/n/943186.html

相关文章

HDU1263,水果(STL)

用map操作 代码如下&#xff1a; #include<iostream> #include<map> #include<set> #include<string> using namespace std; struct fruit {string name;string place;bool operator < (const fruit& b) const{if(b.place!place)return b.plac…

HDU1896,Stones(STL)

用优先队列模拟就行了&#xff0c;只不过题意要理解好&#xff1a;当奇数次遇到石子时就丢石子&#xff0c;否则就弃石子。个人觉得题意描述得挺模糊的&#xff0c;容易让人石子的编号是奇数时丢石子。 代码如下&#xff1a; #include<iostream> #include<queue>…

C++图论——最小生成树

板题——最优布线问题 题目描述 学校有n台计算机&#xff0c;为了方便数据传输&#xff0c;现要将它们用数据线连接起来。两台计算机被连接是指它们中间有数据线连接。由于计算机所处的位置不同&#xff0c;因此不同的两台计算机的连接费用往往是不同的。 当然&#xff0c;如果…

bzoj 1977: [BeiJing2010组队]次小生成树

Description 小 C 最近学了很多最小生成树的算法&#xff0c;Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时&#xff0c;小 P 又来泼小 C 冷水了。小 P 说&#xff0c;让小 C 求出一个无向图的次小生成树&#xff0c;而且这个次小生成树还得是严格次小的&…

HDU1022,Train Problem I(栈)

明显要用栈来模拟。 突破口&#xff1a;找栈顶 解析将在代码中体现。 #include<stack> #include<vector> #include<string> #include<cstring> #include<iostream> using namespace std; stack<char> p; vector<string> v; char s1…

C++迭代加深——Addition Chains(ZOJ 1937)详解

引言 茕茕孑立&#xff0c;迭代加深。。。 题目描述 Addition Chains 已知一个数列 &#xff08;其中 &#xff09;。对于每个 &#xff0c;需要满足 &#xff08;&#xff0c;这里 与 可以相等&#xff09;。 现给定 的值&#xff0c;要求 的最小值&#xff08;并不要求输…

bzoj 2338: [HNOI2011]数矩形

Description 计算几何。枚举边&#xff0c;长度和中点都相同即可构成矩形&#xff0c;差积计算面积即可 #include<cstdio> #include<algorithm> using namespace std; int p; struct point {long long x,y; }a[1501]; struct line {long long x1,y1,x2,y2;long lon…

POJ2833,The Average(优先队列)

突破口&#xff1a;开两个优先队列q_ma,q_mi&#xff0c;前者维护前n1个最大的数&#xff0c;后者维护后n2个最小的数。 原本打算用一个优先队列存储数据&#xff0c;但是如果全部都存的话会爆内存&#xff0c;而且还可能会超时&#xff0c;然后就想能不能用一个优先队列来存n…