您的位置:首页 > 其它

BZOJ1875 [SDOI2009]HH去散步(矩阵乘法)

2015-06-26 03:06 405 查看
【题解】

小规模图的连通性问题,可以用邻接矩阵+快速幂求解

本题唯一特殊的一点就是:

不能沿着刚刚走来的路走回,注意:不是不能走重边,而是不能反向走刚刚走过的边

处理方法是将无向边拆成两条有向边,互换点与边的地位,即:将两条有向边按是否首尾相接建立邻接矩阵

所有边Ei:u->v与Ej:v->w(w!=u),都有 Y[i][j]=1

此时Y[i][j]=1的意义是:从边i的末端走一步能到达边j的末端,有1种方案

由于 Y[i][ i的反向边 ]==0,所以避免了"沿着刚刚走来的路走回"的情况

只需将这个矩阵自乘t-1次,Y[i][j]就代表从边i的始端走t步到达边j的末端的方案数,自乘的原理是乘法原理

又因为起点规定好是A,再构造一个系数矩阵X,使其与Y相乘后仅保留Y[i][j]中i的起点是A的位置,累加终点是B的边j的答案即可

【代码】

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MOD 45989
int v[125],first[25],next[125];
int e=0;
struct juzhen
{
	int s[125][125];
	juzhen()
	{
		memset(s,0,sizeof(s));
	}
};
juzhen cheng(juzhen a,juzhen b)
{
	juzhen res;
	int i,j,k;
	for(i=1;i<=e;i++)
		for(j=1;j<=e;j++)
		{
			for(k=1;k<=e;k++)
				res.s[i][j]+=a.s[i][k]*b.s[k][j]%MOD;
			res.s[i][j]%=MOD;
		}
	return res;
}
juzhen ksm(juzhen a,int n)
{
	juzhen res;
	if(n==1) return a;
	res=ksm(a,n/2);
	res=cheng(res,res);
	if(n&1) res=cheng(res,a);
	return res;
}
void tj(int x,int y)
{
	v[++e]=y;
	next[e]=first[x];
	first[x]=e;
}
int fan(int x)
{
	if(x&1) return x+1;
	return x-1;
}
int main()
{
	juzhen X,Y;
	int n,m,t,A,B,i,j,x,y,ans=0;
	scanf("%d%d%d%d%d",&n,&m,&t,&A,&B);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		tj(x,y);
		tj(y,x);
	}
	for(i=first[A];i!=0;i=next[i])//构造系数矩阵 
		X.s[1][i]=1;
	if(t==0)
	{
		if(A==B) printf("1");
		printf("0");
	}
	else
	{
		if(t>1)
		{
			for(i=1;i<=e;i++)
				for(j=first[v[i]];j!=0;j=next[j])
					if(j!=fan(i)) Y.s[i][j]=1;
			X=cheng(X,ksm(Y,t-1));
		}
		for(i=first[B];i!=0;i=next[i])
			ans+=X.s[1][fan(i)];//边fan(i)的终点是B 
	}
	printf("%d",ans%MOD);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: