版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82250891
graph
题意:一个有向图,从某一点随机出发,问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;
}