【矩阵快速幂】HDOJ graph 5607

graph

 
 Accepts: 9
 
 Submissions: 61
 Time Limit: 8000/4000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

In a directed graph which has NN points and MM edges,points are labled from 1 to n.At first I am at point uu,at each step I will choose an output edge of the current point at uniform random,for every point ZZ,please output the possibility of reaching the point ZZ,moving exactly KK steps.

Input

the first line contains two positive intergesN,MN,M,means the number of points and edges.

next MM lines,contains two positive intergersX,YX,Y,means an directed edge from X to Y.

next line there is an integer QQ,means the number of queries.

next QQ lines,each line contains two integers u,Ku,K,means the first point and number of the steps.

N\le 50,M\le 1000,Q\le 20,u\le N,K\le 10^9N50,M1000,Q20,uN,K109.

Every point have at least one output edge.

Output

QQ lines,each line contains NN numbers,the ii-th number means the possibility of reaching point ii from uu,moving exactly KK steps.

In consideration of the precision error,we make some analyses,finding the answer can be represented as the form like \frac{X}{Y}YX,you only need to output X\times Y^{10^9+5}~mod~(10^9+7)X×Y109+5 mod (109+7).

You need to output an extra space at the end of the line,or you will get PE.

Sample Input
3 2
1 2
1 3
1
1 1
Sample Output
0 500000004 500000004 

I am now at point 11,by one move,with a possibity of \frac{1}{2}21 of reaching point 2,with a possibity of \frac{1}{2}21 of reaching point 3,so we need to output 0 0.5 0.5,but as what is said above,we need to output1*2^{10^9+5}~mod~{10^9+7}=50000000412109+5 mod 109+7=500000004.

中文题:

graph

 
 Accepts: 30
 
 Submissions: 188
 Time Limit: 8000/4000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
在一个NN个点(标号11~nn),MM条边的有向图上,一开始我在点uu,每一步我会在当前点的出边中等概率的选一条走过去,求走了恰好KK步后走到每个点的概率.
输入描述
第一行两个正整数N,MN,M,表示点数和边数.
接下来MM行,每行两个正整数X,YX,Y.表示一条XXYY的一条有向边(保证没有重边和自环).
接下来一个正整数QQ,表示询问个数.
接下来QQ行,每行两个正整数u,Ku,K,表示开始的点和步数.
N \leq 50, M \leq 1000, Q \leq 20, u \leq n, K \leq 10^{9}N50,M1000,Q20,un,K109.
每个点保证至少有一个出边.
输出描述
QQ行,每行NN个数字,用空格隔开,第ii个数字表示从uu开始走KK步到ii的概率.
考虑到输出的答案可能会有精度问题,经过一定的分析后可以发现答案一定可以被表示成\frac{X}{Y}YX的形式,你只需输出X \times Y^{10^9+5} \ mod \ (10^9+7)X×Y109+5 mod (109+7)的值即可.

在每行后面多输出一个空格,否则可能会使你PE.
输入样例
3 2
1 2
1 3
1
1 1
输出样例
0 500000004 500000004 
Hint
这是一个三个点,两条边的有向图,它们分别是(1->2,1->3)(1>2,1>3).现在在1号点,走了一步后,有1/2的概率走到了2,有1/2的概率走到了3,本来应该输出 0 0.5 0.5
而根据上面所说的,应输出1*2^{10^9+5} \ mod \ (10^9+7)=50000000412109+5 mod (109+7)=500000004.

解题思路:

graph

考虑dpdpdp,用ft,xf_{t,x}ft,x表示第ttt秒在xxx的概率,初始时f0,u=1f_{0,u}=1f0,u=1.

ft+1,y=∑x,x−>yft,xOutx,Outxf_{t+1,y}=\sum_{x,x->y}{\frac{f_{t,x}}{Out_x}},Out_xft+1,y=x,x>yOutxft,x,Outx表示xxx的出度.

因为ttt很大,而且发现每次的转移都是相同的,所以直接矩乘就好了.

复杂度是O(QN3logt)O(QN^3\log t)O(QN3logt).

考虑成矩阵就是i到j的概率,初始化矩阵就是第一步的情况。进行k次相乘就是结果了。

注意结果要求,初始化数据出度进行一次快速幂就可以了。

AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long LL;

const LL Mod=1000000007;
const LL expn=1000000005;
const int MAXN = 55;

struct Matrix
{
    LL a[MAXN][MAXN];
    int r,c;
};

Matrix multiply(Matrix x,Matrix y)
{
    Matrix z;
    z.r=x.r;z.c=y.c;
    for(int i=0;i<z.r;i++){
    	for(int j=0;j<z.c;j++)
    	z.a[i][j]=0;
	}
    for(int i=0;i<x.r;i++){
        for(int k=0;k<x.c;k++){
            if(x.a[i][k]){
                for(int j=0;j<y.c;j++){
                    z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%Mod)%Mod;
                }
            }
        }
    }
    return z;
}

Matrix Mpower(Matrix x,int n)
{
    Matrix res;
    res.r=x.r;res.c=x.c;
    for(int i=0;i<res.r;i++){
        for(int j=0;j<res.c;j++){
            if(i==j)res.a[i][j]=1;
            else res.a[i][j]=0;
        }
    }
    while(n){
        if(n&1) res=multiply(res,x);
        x=multiply(x,x);
        n>>=1;
    }
    return res;
}

void Mpr(Matrix x)
{
    for(int i=0;i<x.r;i++){
        for(int j=0;j<x.c;j++){
            printf("%d ",x.a[i][j]);
        }
        printf("\n");
    }
}

LL power(LL x,LL n)
{
    LL res=1;
    while(n){
        if(n&1) res=res*x%Mod;
        x=x*x%Mod;
        n>>=1;
    }
    return res;
}

bool vis[MAXN][MAXN];
LL degree[MAXN];

int main()
{
    int N,M;
    while(scanf("%d%d",&N,&M)!=EOF){
        int X,Y;
        memset(degree,0,sizeof(degree));
        memset(vis,false,sizeof(vis));
        for(int i=0;i<M;i++){
            scanf("%d%d",&X,&Y);
            vis[X-1][Y-1]=true;
            degree[X-1]++;
        }
        Matrix temp;
        for(int i=0;i<N;i++){
            LL t=power(degree[i],expn);
            for(int j=0;j<N;j++){
                if(vis[i][j]){
                    temp.a[i][j]=t;
                }
            }
        }
        temp.r=temp.c=N;
        int Q;
        scanf("%d",&Q);
        while(Q--){
            int u,K;
            scanf("%d%d",&u,&K);
            Matrix ans;
            ans=Mpower(temp,K);
            for(int i=0;i<N;i++){
                printf("%lld ",ans.a[u-1][i]);
            }
            printf("\n");
        }
    }
    return 0;
}


你可能感兴趣的:(【矩阵快速幂】HDOJ graph 5607)