题意:给一个无向图,要在这个图上走d步,每个点被选为起点的概率相同,每个点到和它相邻的点的概率相同。求d步都没走到某个点的概率。
http://acm.hdu.edu.cn/showproblem.php?pid=5001
感觉很简单的样子,但是比赛的时候就是连样例都过不了QAQ。。。
看别人的题解说是每次删掉一的点,走d步到达其他点的概率之和就是d步都不到这个点的概率(ans[i] = ∑p[d][i])。
但是这是为什么呢?
首先,p[i][j]表示第i步走到j的概率,p[i][j] = ∑p[i - 1][v] / e;(v是和j相邻的顶点,e是以v为起点的边数)
一下子想不出来ans[i] = ∑p[d][i]
我们先想只走一步。这样就变成了前1步不走cur的概率 = 第一步走到其他点的概率和。这显然成立。。。
然后我们再想要走两步的情况:前2步不走cur的概率 = 第2步走到其他点的概率和。想到这时已经保证了第1步不走cur,相当于保证了前2步都不走cur!
所以等式成立。
推广到走d步。前d步都不走到cur的情况下走到其他点的概率之和就是ans[cur]!
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double DB;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const DB eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int mod = 10000007;
const int maxn = 2000 + 10;
int T, n, m, d;
DB p[11111][55], ans[55];
vector<int> V[55];
int main(){
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &m, &d);
for(int i=1; i<=n; i++) V[i].clear();
for(int i=1; i<=m; i++){
int a, b;
scanf("%d%d", &a, &b);
V[a].pb(b);
V[b].pb(a);
}
for(int cur=1; cur<=n; cur++){///枚举不走的点
memset(p, 0, sizeof(p));
for(int i=1; i<=n; i++) p[0][i] = 1.0 / n;///选每个点做起点的概率都是1/n
for(int i=1; i<=d; i++){
for(int j=1; j<=n; j++) if(j != cur){///不从cur走
for(unsigned k=0; k<V[j].size(); k++){///枚举所有和j相邻的点
int v = V[j][k];
p[i][v] += p[i - 1][j] / (DB)V[j].size();///p[i][v]表示第i步到v的概率
}
}
}
ans[cur] = 0.0;
for(int i=1; i<=n; i++) if(i != cur){
ans[cur] += p[d][i];
}
}
for(int i=1; i<=n; i++) printf("%.10f\n", ans[i]);
}
return 0;
}
比赛的时候我们是分别从每个点出发,计算第i步到j的概率,再把每步不到j的概率乘起来,就是每步都不到j的概率。