zoukankan      html  css  js  c++  java
  • [矩阵加速]道路千万条

    题目描述

    道路千万条,安全第一条!HF校区到YB校区有很多种走法,我们可以把走法看成N个节点的有向图,假设HF代表0号节点,YB代表N-1号节点,GM想从0号节点出发,到N-1号节点,但必须恰好在T时刻到达!你能告诉GM一共有多少种走法吗?注意:GM不能在某个节点逗留,且通过某有向边时严格为给定时间(边权)。

    输入

    满足 2 <= N <= 10 ; 1 <= T <= 1000000000。
    输出
    包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。
    样例输入
    2 2
    11
    00
    样例输出
    1

    解题思路

    首先想一个简单的情况,如果只是有0,1所组成的矩阵我们该如何求呢
    例如egin{bmatrix} 1 & 0\ 0 & 1 end{bmatrix}

    这里有一个性质,也就是这一个矩阵的t次幂所在的s[i][j]正是从i到j的时间为t的路径数。

    震惊吧,我也很震惊...

    仔细想一想其实也确实是这样。

    我们先看2次方

    egin{bmatrix} 1 * 1 + 0 * 0&1 * 0 + 0 * 1\ 0 * 1 + 1 * 0&1 * 1 + 0 * 1 end{bmatrix}

    (1,1)就是意义为1到1中途经过1的情况,就相当于走了2(时间)。而(1,2)则是1到2中途经过2的情况,这样推下去确实也没有问题,因为(i,j)为1则就说明了i,j有路。

    其实我们回到矩阵乘法的基本定义

    其实也就这么做出来。

    但这道题又不是由0,1构成,我们就需要拆点。

    例如egin{bmatrix} 0 & 2\ 2 & 1 end{bmatrix}

    我们就拆成了

    egin{bmatrix} 0 & 1 & 0 &0 \ 0 &0 &1 &0 \ 0 & 0 & 1 &1 \ 1 & 0 & 0 &0 end{bmatrix}

    我们就是将每一个点拆成它的最大边权个(这样才能构造出全部为1,0)

    拆点过程呢...看代码吧,我觉得自己想一下还是可以理解的。(模板大法好)

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    using namespace std;
    struct matrix {
        int n,m;
        long long c[150][150];
        matrix (){
            memset(c,0,sizeof(c));
        }
        matrix operator * (const matrix &x)const{
            matrix tmp ;
            tmp.n = n;
            tmp.m = x.m;
            for (int i = 1;i <= tmp.n;i ++)
                for (int j = 1;j <= tmp.m;j ++)
                    for (int k = 1;k <= x.n;k ++)
                        tmp.c[i][j] = (tmp.c[i][j] + c[i][k] * x.c[k][j]) % 2009;
            return tmp;
        }
    }A,B;
    int n,t;
    long long maxn;
    int xb(int x,int y){
        return (x - 1) * maxn + y;
    }
    matrix qkpow(matrix x,int y){
        matrix ans;
        ans.n = ans.m = x.n;
        for (int i = 1;i <= ans.n;i ++)
            ans.c[i][i] = 1;
        while (y){
            if (y & 1)
                ans = ans * x;
            x = x * x;
            y /= 2;
        }
        return ans;
    }
    int main(){
        scanf ("%d%d",&n,&t);
        for (int i = 1;i <= n;i ++)
            for (int j = 1;j <= n;j ++){
                scanf ("%1lld",&A.c[i][j]);
                maxn = max(A.c[i][j],maxn);
            }
        for (int i = 1;i <= n;i ++){
            for (int j = 1;j < maxn;j ++)
                B.c[xb(i,j)][xb(i,j+1)] = 1;
            for (int j = 1;j <= n;j ++){
                if (A.c[i][j] != 0)
                    B.c[xb(i,A.c[i][j])][xb(j,1)] = 1;
            }
        }
        B.n = B.m = maxn * n;
        B = qkpow(B,t);
        printf("%lld
    ",B.c[1][(n - 1) * maxn + 1]);
    }

    花絮

    广搜爆炸

    深搜爆炸

    (搜索真好用)

  • 相关阅读:
    隐性改变display类型
    垂直居中-父元素高度确定的多行文本(方法二)
    去掉WIN7 桌面图标的小箭头
    搭建高可用mongodb集群(三)—— 深入副本集内部机制
    搭建高可用mongodb集群(二)—— 副本集
    搭建高可用mongodb集群(一)——配置mongodb
    Linux:Tomcat报错: Error creating bean with name 'mapScheduler' defined in ServletContext resource 的解决方法
    LINUX ORACLE 启动与关闭
    Linux 安装 Oracle 11g R2
    ORACLE 数据库优化原则
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566681.html
Copyright © 2011-2022 走看看