graph
Accepts: 30
Submissions: 188
Time Limit: 8000/4000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
在一个NNN个点(标号111~nnn),MMM条边的有向图上,一开始我在点uuu,每一步我会在当前点的出边中等概率的选一条走过去,求走了恰好KKK步后走到每个点的概率.
输入描述
第一行两个正整数N,MN,MN,M,表示点数和边数. 接下来MMM行,每行两个正整数X,YX,YX,Y.表示一条XXX向YYY的一条有向边(保证没有重边和自环). 接下来一个正整数QQQ,表示询问个数. 接下来QQQ行,每行两个正整数u,Ku,Ku,K,表示开始的点和步数. N≤50,M≤1000,Q≤20,u≤n,K≤109N \leq 50, M \leq 1000, Q \leq 20, u \leq n, K \leq 10^{9}N≤50,M≤1000,Q≤20,u≤n,K≤109. 每个点保证至少有一个出边.
输出描述
QQQ行,每行NNN个数字,用空格隔开,第iii个数字表示从uuu开始走KKK步到iii的概率. 考虑到输出的答案可能会有精度问题,经过一定的分析后可以发现答案一定可以被表示成XY\frac{X}{Y}YX的形式,你只需输出X×Y109+5 mod (109+7)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−>2,1−>3).现在在1号点,走了一步后,有1/2的概率走到了2,有1/2的概率走到了3,本来应该输出 0 0.5 0.5 而根据上面所说的,应输出1∗2109+5 mod (109+7)=5000000041*2^{10^9+5} \ mod \ (10^9+7)=5000000041∗2109+5 mod (109+7)=500000004. ac 代码 在矩阵初始化时不是0,1 而是概率的x/y的形势,a【i】【j】x是从i第k步到达j的方案数,而y是走k步的总方案数。 这样矩阵的k次幂后a【i】【j】代表从i走k步到j的概率。#include<stdio.h> #include<math.h> #include<stdlib.h> #include<algorithm> #include<string.h> #include<vector> using namespace std; typedef long long LL; const int N = 50; const int M = 1e9+7; int out[55]; struct Matri{ Matri(){ memset(a,0,sizeof(a)); } LL a[N+5][N+5]; }bs,A ; Matri operator *(Matri a,Matri b) { int i,j,k; Matri tmp; for(i=1;i<=N;i++){ for(j=1;j<=N;j++){ tmp.a[i][j] = 0; for(k=1;k<=N;k++) { tmp.a[i][j] =(tmp.a[i][j] + 1LL*a.a[i][k] * b.a[k][j])%M; // ? } } } return tmp; } Matri pw(Matri a, int k){ //a的k次幂 int i; Matri tmp; memset(tmp.a,0,sizeof(tmp.a)); for(i=0;i<=N;i++) tmp.a[i][i] = 1; while(k){ if(k%2){ tmp = tmp*a; // 前后顺序 } a = a * a; k/=2; } return tmp; } LL pw(LL a,int k){ //a的k次幂 int i; LL tmp = 1; while(k){ if(k%2){ tmp = (a * tmp)%M; // 前后顺序 } a = (a * a)%M; k/=2; } return tmp; } Matri work(int k){ int i,j; Matri tmp; tmp = pw(bs,k); return tmp; } void prit(Matri t){ int i,j; for(i=1;i<=3;i++){ for(j=1;j<=3;j++){ printf("%d ",t.a[i][j]); } printf("\n"); } } int main() { int i,j,k,n,m,q; int u,v; int st; LL now; //printf("%I64d\n",pw(2,M-2)); scanf("%d%d",&n,&m); memset(bs.a,0,sizeof(bs.a)); for(i=0;i<m;i++){ scanf("%d%d",&u,&v); bs.a[u][v] = 1; out[u]++; } for(i=1;i<=n;i++){ now = pw(out[i],M-2); for(j=1;j<=n;j++) bs.a[i][j] = (bs.a[i][j] * now )%M; } //!! no above 5 line just wrong scanf("%d",&q); while(q--){ Matri ans; LL total = 0; scanf("%d%d",&st,&k); ans = work(k); for(i=1;i<=n;i++){ printf("%I64d ",ans.a[st][i]); } puts(""); } return 0; }
问题是wrong代码:
唯一不同就是矩阵存的是方案数。
于是进行了矩阵的k次幂后,我在求i到j走k步的方案数a【i】【j】(题意中x),然后得到i走k步的总方案数a【i】【1】+。。。+a【i】【n】(题意中y),然后X×Y109+5 mod (109+7)。有问题么??????????
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
typedef long long LL;
const int N = 50;
const int M = 1e9+7;
int out[55];
struct Matri{
Matri(){
memset(a,0,sizeof(a));
}
LL a[N+5][N+5];
}bs,A ;
Matri operator *(Matri a,Matri b)
{
int i,j,k;
Matri tmp;
for(i=1;i<=N;i++){
for(j=1;j<=N;j++){
tmp.a[i][j] = 0;
for(k=1;k<=N;k++)
{
tmp.a[i][j] =(tmp.a[i][j] + 1LL*a.a[i][k] * b.a[k][j])%M; // ?
}
}
}
return tmp;
}
Matri pw(Matri a, int k){ //a的k次幂
int i;
Matri tmp;
memset(tmp.a,0,sizeof(tmp.a));
for(i=0;i<=N;i++)
tmp.a[i][i] = 1;
while(k){
if(k%2){
tmp = tmp*a; // 前后顺序
}
a = a * a;
k/=2;
}
return tmp;
}
LL pw(LL a,int k){ //a的k次幂
int i;
LL tmp = 1;
while(k){
if(k%2){
tmp = (a * tmp)%M; // 前后顺序
}
a = (a * a)%M;
k/=2;
}
return tmp;
}
Matri work(int k){
int i,j;
Matri tmp;
tmp = pw(bs,k);
return tmp;
}
void prit(Matri t){
int i,j;
for(i=1;i<=3;i++){
for(j=1;j<=3;j++){
printf("%d ",t.a[i][j]);
}
printf("\n");
}
}
int main()
{
int i,j,k,n,m,q;
int u,v;
int st;
LL now;
//printf("%I64d\n",pw(2,M-2));
scanf("%d%d",&n,&m);
memset(bs.a,0,sizeof(bs.a));
for(i=0;i<m;i++){
scanf("%d%d",&u,&v);
bs.a[u][v] = 1;
// out[u]++;
}
//prit(bs);
// for(i=1;i<=n;i++){
// now = pw(out[i],M-2);
// for(j=1;j<=n;j++)
// bs.a[i][j] = (bs.a[i][j] * now )%M;
// }
//prit(bs); //!! no above 5 line just wrong
scanf("%d",&q);
while(q--){
Matri ans;
LL total = 0;
scanf("%d%d",&st,&k);
ans = work(k);
for(i=1;i<=n;i++){
//for(j=1;j<=n;j++)
total = (total + ans.a[st][i])%M ;
}
total = pw(total,M-2);
for(i=1;i<=n;i++){
printf("%I64d ",(1LL*ans.a[st][i] * total)%M );
}
printf("\n");
}
return 0;
}