zoukankan      html  css  js  c++  java
  • 【bzoj1875】[SDOI2009]HH去散步 矩阵乘法

    题目描述

    一张N个点M条边的无向图,从A走到B,要求:每一次不能立刻沿着上一次的的反方向返回。求方案数。

    输入

    第一行:五个整数N,M,t,A,B。
    N表示学校里的路口的个数
    M表示学校里的路的条数
    t表示HH想要散步的距离
    A表示散步的出发点
    B则表示散步的终点。
    接下来M行
    每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。
    数据保证Ai != Bi,但不保证任意两个路口之间至多只有一条路相连接。 
    路口编号从0到N -1。 
    同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 
    答案模45989。
    N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

    输出

    一行,表示答案。

    样例输入

    4 5 3 0 0
    0 1
    0 2
    0 3
    2 1
    3 2

    样例输出

    4


    题解

    矩阵乘法

    “每一次不能立刻沿着上一次的边的反方向返回”这个条件的限制导致不能直接进行矩阵乘法。

    由于边数很少,我们可以换个思路:把边看作矩阵乘法的行列,矩阵中的元素表示 从一条边走到另一条边的方案数。

    那么对于两条边$i,j$,如果不是刚走过来的边并且能够接上($y_i=x_j$),则$A_{ij}=1$。

    然后建立两个虚点,第一个向起点为s的边连边,起点为t的项第二个连边。

    然后快速幂矩阵乘法即可。

    时间复杂度$O(m^3log t)$

    #include <cstdio>
    #include <cstring>
    #define N 130
    #define mod 45989
    int m , px[N] , py[N];
    struct data
    {
    	int v[N][N];
    	data() {memset(v , 0 , sizeof(v));}
    	int* operator[](int a) {return v[a];}
    	data operator*(data a)
    	{
    		data ans;
    		int i , j , k;
    		for(i = 0 ; i <= m ; i ++ )
    			for(j = 0 ; j <= m ; j ++ )
    				for(k = 0 ; k <= m ; k ++ )
    					ans[i][j] = (ans[i][j] + v[i][k] * a[k][j]) % mod;
    		return ans;
    	}
    }a;
    data pow(data x , int y)
    {
    	data ans;
    	int i;
    	for(i = 0 ; i <= m ; i ++ ) ans[i][i] = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x;
    		x = x * x , y >>= 1;
    	}
    	return ans;
    }
    int main()
    {
    	int n , k , s , t , i , j;
    	scanf("%d%d%d%d%d" , &n , &m , &k , &s , &t);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &px[i << 1] , &py[i << 1]) , px[i << 1 | 1] = py[i << 1] , py[i << 1 | 1] = px[i << 1];
    	m = m * 2 + 1;
    	for(i = 2 ; i <= m ; i ++ )
    	{
    		if(px[i] == s) a[0][i] = 1;
    		if(py[i] == t) a[i][1] = 1;
    		for(j = 2 ; j <= m ; j ++ )
    			if(py[i] == px[j] && (i ^ j) != 1)
    				a[i][j] = 1;
    	}
    	a = pow(a , k + 1);
    	printf("%d
    " , a[0][1]);
    	return 0;
    }
    
  • 相关阅读:
    java基础知识——7.断点调试与数据加密
    Hibernate最基础配置的记忆方式
    Redis集群命令
    VMware Workstation下centos的使用
    Redis入门
    Shell脚本
    使用Java遇到的问题
    使用Linux
    压缩包安装MySQL服务
    安装windows+ubuntu双系统
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7602896.html
Copyright © 2011-2022 走看看