BZOJ4887可乐——矩阵乘法

Description
加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且
放在了加里敦星球的1号城市上。这个可乐机器人有三种行为:停在原地,去下一个相邻的
城市,自爆。它每一秒都会随机触发一种行为。现在给出加里敦星球城市图,在第0秒时可
乐机器人在1号城市,问经过了t秒,可乐机器人的行为方案数是多少?
Input
第一行输入两个正整数N,M表示城市个数,M表示道路个数。(1≤N≤30,0≤M≤100)
接下来M行输入u,v表示u,v之间有一条道路。
(1≤u,v≤n)保证两座城市之间只有一条路相连。
最后输入时间t。1<t≤10^6
Output

输出可乐机器人的行为方案数,答案可能很大,请输出对2017取模后的结果。
Sample Input
3 2

1 2

2 3

2
Sample Output
8


这道题我们用邻接矩阵存储,因为邻接矩阵是可以进行矩阵乘法转移的。
首先我们先去掉所有的条件,即机器人只能向相邻的点走,不能停留,也不能自爆。那么只要将读入的邻接矩阵转移t次即可。
那么我们再考虑停留和自爆的情况。停留就是下一步还在该点,所以我们在初始的矩阵中对于每个点x,连接一条x到x的边(自环)即可。这样进行转移的时候就有自己走向自己的转移,也就相当于停在当地。
自爆后就不能再走了,就相当一个点走到死胡同里,出不去了。所以我们建一个新节点n+1,将每个点都与其连边。但它只与自己连边(爆炸后一直处于爆炸情况不能进行转移,就相当于自己一直转移到自己)
于是将新建的矩阵进行t次转移,然后统计所有点与1点形成的值即可。
#include<bits/stdc++.h>
#define MD 2017
using namespace std;
int read(){
	char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
	while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,m,cnt,t,ans,f[35][35],a[35][35],u[35][35];
void mul(int a[][35],int b[][35]){
	for(int i=1;i<=n+1;i++)
	 for(int j=1;j<=n+1;j++){
	 	int res=0;
	 	for(int k=1;k<=n+1;k++) 
		  (res+=a[i][k]*b[k][j])%=MD;
	 	u[i][j]=res;
	 }
	for(int i=1;i<=n+1;i++)
	 for(int j=1;j<=n+1;j++)
	  a[i][j]=u[i][j];
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		f[x][y]=f[y][x]=1;
	}
	for(int i=1;i<=n;i++){
		f[i][i]=1;f[i][n+1]=1;
	}
	f[n+1][n+1]=1;t=read();
	for(int i=1;i<=n+1;i++) a[i][i]=1;
	while(t){
		if(t&1) mul(a,f);
		mul(f,f);t/=2;
	}
	for(int i=1;i<=n+1;i++)(ans+=a[1][i])%=MD;
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值