zoukankan      html  css  js  c++  java
  • 1482 路线统计

    1482 路线统计

     

     时间限制: 1 s
     空间限制: 256000 KB
     题目等级 : 钻石 Diamond
     
     
    题目描述 Description

    N个节点的有向图, 求从start到finish刚好经过时间time的总方案数 mod 502630.

    输入描述 Input Description

    第一行包含一个整数n, 所有点是从0到N-1编号.

           接下来n行,每行包含n个字符. 第i行第j个字符表示i到j需要的时间. 字符只可能是’1’到’5’, 或者是’.’表示i不能到达j. 保证主对角线都是’.’.

           接下来一行3个整数start, finish, time.

    输出描述 Output Description

    输出总方案数.

    样例输入 Sample Input

           3

           .12

           2.1

           12.

           0 2 5

    样例输出 Sample Output

    8

    数据范围及提示 Data Size & Hint

           对于20%的数据, 输入的字符不是’1’就是’.’;

           对于100%的数据, 1 <= n <= 10; 1 <= start,finish <= n; 1 <= time <= 10^9.

    分类标签 Tags 点此展开 

     

    【解题报告】

    第一眼,dfs,但看t的范围,显然超时。

    再看,点很少(矩阵的n次幂耗时少),时间很多(走法复杂)

    矩阵乘法的标志啊!!!

       

    我们知道无边权图从s经k步到f怎么求:即01矩阵:

    建立矩阵A  当且仅当存在一条边i->j ,A(i,j)=1。

    令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)

    类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。

    同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。

    但图有边权,怎么办?

    两个字:拆点!

    将每个点之间的关系用矩阵存储,i能1步到j标记为1,不能到标记为0,注意题中边权为1-5,则可拆点,将每个点拆成边权个点,如图:

    但这样还不够,我们要建(n*n*5)^2 = 500*500的矩阵,矩阵乘法t达到500 ^ 3 这显然太多了。

    于是:我们遇到一个边i,j,权为c,把它拆成i –> i+n*1 -> i+n*2 ->… -> i+n*(c-1)-> j

    如图:

    于是就只有(n*5)^2=50*50的矩阵了。

    拆完点,矩阵就变成了01矩阵

    则这个矩中的A[i][j]就保存了1步能从i到j的方案数,要求t步,则直接将矩阵自乘t次即得答案。

    2017-03-25

    #include<cstdio>
    typedef long long ll;
    const ll mod=502630;
    struct matrix{ll s[50][50];}A;
    char s[11];int n,S,T,K;
    matrix operator *(const matrix &a,const matrix &b){
        matrix c;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                c.s[i][j]=0;
                for(int k=0;k<n;k++){
                    c.s[i][j]+=a.s[i][k]*b.s[k][j];
                    c.s[i][j]%=mod;
                }
            }
        }
        return c;
    }
    matrix fpow(matrix a,ll p){
        matrix ans;
        for(int i=0;i<n;i++) ans.s[i][i]=1;
        for(;p;p>>=1,a=a*a) if(p&1) ans=ans*a;
        return ans;
    }
    int main(){
        scanf("%d",&n);
        for(int i=0,cnt;i<n;i++){
            scanf("%s",s);
            for(int j=0;j<n;j++){
                if(s[j]>='0'&&s[j]<='9'){
                    cnt=s[j]-'0';
                    for(int k=1;k<cnt;k++) A.s[n*(k-1)+i][n*k+i]=1;
                    A.s[n*(cnt-1)+i][j]=1;
                }
            }
        }
        n*=5;
        scanf("%d%d%d",&S,&T,&K);
        A=fpow(A,K);
        printf("%lld
    ",A.s[S][T]);
        return 0;
    }

    2016-08-05

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int mod=502630;
    int f,t,s,n;
    char c;
    int ans;
    int cnt;
    struct node{
        int f[60][60];
    }E,x;
    void clean(){
        for(int i=0;i<=n;i++) E.f[i][i]=1;
    }
    node cheng(node a,node b){    //矩阵乘法
        node ne;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                ne.f[i][j]=0;
                for(int k=0;k<n;k++) ne.f[i][j]=(ne.f[i][j]+((long long)a.f[i][k]*b.f[k][j])%mod)%mod;
            }
        }
        return ne;
    }
    int answer(){
        node ne=x;
        node ass=E;
        int b=t;
        while(b){      //矩阵求幂
            if(b&1) ass=cheng(ass,ne);
            b>>=1;
            ne=cheng(ne,ne);
        }
        return ass.f[s][f];
    }
    int main(){
        scanf("%d
    ",&n);
        cnt=n;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                scanf("%c",&c);
                if(c>='0'&&c<='9'){    
                    cnt=c-'0';
                    for(int k=1;k<cnt;k++) x.f[n*(k-1)+i][n*k+i]=1; //拆点
                    x.f[n*(cnt-1)+i][j]=1;
                }
            }
            scanf("
    ");
        }
        n*=5;                       //最后n要乘5
        scanf("%d%d%d",&s,&f,&t);
        clean();                    //定义单位矩阵
        printf("%d
    ",answer());
        return 0;
    }
  • 相关阅读:
    【小程序】文本超出则省略号
    【wx小程序】读懂app.js
    【js】某字符串多次替换
    【小程序】本地资源图片无法通过 WXSS 获取
    【小程序】(一)注册开始小程序开发
    【小程序】配置本地接口开发
    【css】文本超出行数以省略号显示
    【webstorm】project目录树显示不出
    【Nodejs】Browsersync同步浏览器测试
    获取指定包名下继承或者实现某接口的所有类(扫描文件目录和所有jar)
  • 原文地址:https://www.cnblogs.com/shenben/p/5739805.html
Copyright © 2011-2022 走看看