hdoj 5607 graph 【矩阵快速幂】



graph

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 103    Accepted Submission(s): 53


Problem Description
In a directed graph which has  N  points and  M  edges,points are labled from 1 to n.At first I am at point  u ,at each step I will choose an output edge of the current point at uniform random,for every point  Z ,please output the possibility of reaching the point  Z ,moving exactly  K  steps.
 

Input
the first line contains two positive interges N,M ,means the number of points and edges.

next  M  lines,contains two positive intergers X,Y ,means an directed edge from X to Y.

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

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

N50,M1000,Q20,uN,K109 .

Every point have at least one output edge.
 

Output
Q  lines,each line contains  N  numbers,the  i -th number means the possibility of reaching point  i  from  u ,moving exactly  K  steps.

In consideration of the precision error,we make some analyses,finding the answer can be represented as the form like  XY ,you only need to output  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 $1$,by one move,with a possibity of $\frac{1}{2}$ of reaching point 2,with a possibity of $\frac{1}{2}$ of reaching point 3,so we need to output 0 0.5 0.5,but as what is said above,we need to output$1*2^{10^9+5}~mod~{10^9+7}=500000004$.
 




问题描述
在一个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.


只能说自己太SB了!!!


思路:设置P[k][i]为第k步到达i点的概率。

那么P[k+1][i] = sigma(P[k][j] * idv(degree[j])) (1 <= j <= N && Map[j][i] == 1)。

求的时候设个逆元就好了,最后结果是一样的。 


AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (50+10)
#define MAXM (500000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
using namespace std;
struct MATRIX{
    struct Matrix{
        LL a[MAXN][MAXN];
        int r, c;
    };
    Matrix ori, res;
    Matrix multi(Matrix x, Matrix y)
    {
        Matrix z; CLR(z.a, 0);
        z.r = x.r; z.c = y.c;
        for(int i = 1; i <= x.r; i++)
        {
            for(int k = 1; k <= x.c; k++)
            {
                if(x.a[i][k] == 0) continue;
                for(int j = 1; 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 Pow(Matrix z, int n)
    {
        Matrix x; x.r = z.r; x.c = z.c;
        for(int i = 1; i <= x.r; i++)
            for(int j = 1; j <= x.c; j++)
                x.a[i][j] = z.a[i][j];
        Matrix y; y.r = y.c = z.r;
        CLR(y.a, 0);
        for(int i = 1; i <= y.r; i++)
            y.a[i][i] = 1;
        while(n)
        {
            if(n & 1)
                y = multi(y, x);
            x = multi(x, x);
            n >>= 1;
        }
        return y;
    }
};
MATRIX solve;
void exgcd(LL a, LL b, LL &d, LL &x, LL &y)
{
    if(!b) {d = a, x = 1, y = 0;}
    else
    {
        exgcd(b, a%b, d, y, x);
        y -= x * (a / b);
    }
}
LL inv(LL a)
{
    LL d, x, y;
    exgcd(a, MOD, d, x, y);
    return (x + MOD) % MOD;
}
int degree[MAXN];
bool Map[MAXN][MAXN];
int main()
{
    int N, M;
    while(scanf("%d%d", &N, &M) != EOF)
    {
        CLR(degree, 0); CLR(Map, false);
        for(int i = 0; i < M; i++)
        {
            int a, b;
            Ri(a); Ri(b);
            Map[a][b] = true;
            degree[a]++;
        }
        for(int i = 1; i <= N; i++)
        {
            LL P = inv((LL)degree[i]);
            for(int j = 1; j <= N; j++)
                if(Map[i][j])
                    solve.ori.a[i][j] = P;
        }
        solve.ori.r = solve.ori.c = N;
        int Q; Ri(Q);
        W(Q)
        {
            int u, k;
            Ri(u); Ri(k);
            solve.res = solve.Pow(solve.ori, k);
            for(int i = 1; i <= N; i++)
                printf("%I64d ", solve.res.a[u][i]);
            printf("\n");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值