您的位置:首页 > 其它

BestCoder Round #68 (div.2) 1003.graph (DP+矩阵快速幂)

2016-01-10 20:38 411 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5607

题意:给一个有向图,点数n(<=50),用邻接矩阵表示,每分钟走一步,每走一步等概率的到达和当前节点相邻的节点,有q(<=20)个查询,每个查询需要你回答从u点出发k(<=1e9)分钟后到达每一个点的概率。

解法:典型的矩阵快速幂。

初始01矩阵第 i 列所有值全部乘以 i 点出度的关于mod的逆元,可得到了初始矩阵。

初始矩阵中的第 i 列为从 i 节点出发0分钟后到达每一个点的概率。k分钟时,邻接矩阵为初始01矩阵的k次幂。输出第u列的值即可。

AC代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
using namespace std;

typedef long long LL;
const int mod=1e9+7;
const int maxn=55;
const int maxm=55;

struct Matrix{
int n,m;
int a[maxn][maxm];
void init(int r,int c){
n=r; m=c;
memset(a,0,sizeof(a));
}
void print(){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
Matrix operator * (const Matrix &b) {
Matrix tmp;
tmp.init(n,b.m);
for(int i=0;i<n;i++){
for(int j=0;j<b.m;j++)
for(int k=0;k<m;k++){
tmp.a[i][j]+=(long long)1*a[i][k]*b.a[k][j]%mod;
tmp.a[i][j]%=mod;
}
}
return tmp;
}
};

Matrix Mpow_mod(LL n,Matrix a){
Matrix ret;
ret.init(a.n,a.n);
for(int i=0;i<ret.n;i++)
ret.a[i][i]=1;
while(n){
if(n&1){
ret=ret*a;
}
a=a*a;
n/=2;
}
//ret.print();
return ret;
}

LL fpow(LL a,LL n){
LL ret=1;
while(n){
if(n&1) ret=ret*a%mod;
a=a*a%mod;
n/=2;
}
return ret;
}

Matrix aa,bb,cc;
int tot[55],mem[55][55];

int main (){
int n,m,x,y,q,u,k;
while(scanf("%d%d",&n,&m)!=EOF){
memset(mem,0,sizeof(mem));
memset(tot,0,sizeof(tot));
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
x--; y--;
mem[x][y]=1;
tot[x]++;
}
aa.init(n,n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
aa.a[i][j]=fpow(tot[i],mod-2)*(LL)mem[i][j]%mod;
//aa.print();
scanf("%d",&q);
while(q--){
scanf("%d%d",&u,&k);
u--;
//cout<<u<<" "<<k<<endl;
bb=Mpow_mod(k,aa);
for(int i=0;i<n;i++)
printf("%d ",bb.a[u][i]);
printf("\n");
}
}
return 0;
}
/*
3 2
1 2
1 3
1
1 1
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: