graph HDU - 5607(矩阵快速幂)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82250891

graph

题目链接:HDU - 5607

题意:一个有向图,从某一点随机出发,问k步之后到达每个点的概率分别是多少;

思路:先不考虑概率问题,只看k步能到达那些点;可以想到离散中学到的矩阵乘;对于现在把路径写成邻接矩阵的形式,那么我们得到的矩阵中dis[u][v]可以表示u->v能否直接到达;将其自乘后就可以得到2步后,dis[u][v]表示u->v能否到达;所以对于k步能否到达就是矩阵的k次方;

现在把概率加上;dis[u][v]=1/degree[u];degree[u]表示u的出度;那么k步后u->v的概率就仍然是矩阵k次方后的dis[u][v];这里题目要求对于概率x/y输出x*y^(1e9+5)%(1e9+7);所以分母一定是degree[u]^(1e9+5);那么直接将他计算出放到矩阵中,在矩阵的快速幂;

最后得到的dis[u][v]就表示k步后u->v的概率(题目要求形式)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
struct node{
	int n;
	ll maxtr[55][55];
};
ll degree[55];
node mul(node a, node b){
	node c;
	c.n=a.n;
	for(int i=0; i<a.n; i++){
		for(int j=0; j<b.n; j++){
			c.maxtr[i][j]=0;
			for(int k=0; k<a.n; k++){
				c.maxtr[i][j]=(c.maxtr[i][j]+a.maxtr[i][k]*b.maxtr[k][j]%mod)%mod;
			}
		}
	}
	return c;
}
ll int_pow(ll ans, ll a, int b){
	while(b){
		if(b&1) ans=(ans*a)%mod;
		b>>=1;
		a=(a*a)%mod;
	}
	return ans;
}
node maxtr_pow(node a, int b){
	node ans;
	ans.n=a.n;
	memset(ans.maxtr, 0, sizeof(ans.maxtr));
	for(int i=0; i<ans.n; i++) ans.maxtr[i][i]=1;
	while(b){
		if(b&1) ans=mul(ans, a);
		b>>=1;
		a=mul(a, a);
	}
	return ans;
}
int main(){
	int n, m;
	while(~scanf("%d%d", &n, &m)){
		node dis;
		dis.n=n;
		memset(dis.maxtr, 0, sizeof(dis.maxtr));
		memset(degree, 0, sizeof(degree));
		for(int i=0; i<m; i++){
			int x, y;
			scanf("%d%d", &x, &y);
			x--, y--;
			degree[x]++;
			dis.maxtr[x][y]=1;
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				dis.maxtr[i][j]=int_pow(dis.maxtr[i][j], degree[i], mod-2);
			}
		}
		int Q;
		scanf("%d", &Q);
		while(Q--){
			int u, k;
			scanf("%d%d", &u, &k);
			u--;
			node temp=dis;
			temp=maxtr_pow(temp, k);
			for(int i=0; i<n; i++)
				printf("%lld ", temp.maxtr[u][i]);
			puts("");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/82250891