第一次做概率dp的题目 ,其处理的方式和普通dp是差不多的,只是将表示的值变成了概率 ,还有就是概率要怎么算是个难题 。
该题求从某个点 i 出发,走d步,不经过i的概率,我们可以求经过 i 的概率,用d[i][j]表示已经走了i步,当前在j点的概率(因为步数是一个天然的序,我们可以用来定义阶段)。
那么显然,如果没有经过j点,概率为0 ,所以初始化为0 ; 每次经过一个点j,那么经过j点的概率就要发生一次变化,假设从k点经过的j点,那么d[i][j]的概率就要加上1/(于k点相连的结点数) ;
所以说,其实和普通的dp一样,还是注意那几个点:阶段、顺序、依赖、d[i[[j]表示的是什么意思、状态如何转移 etc
细节参见代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 55;
int T,n,u,v,m,d;
double dp[10005][55];
vector<int> g[maxn];
void init() {
scanf("%d%d%d",&n,&m,&d);
for(int i=0;i<=n;i++) g[i].clear();
for(int i=0;i<m;i++) {
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
}
double solve(int u) {
memset(dp,0,sizeof(dp));
dp[0][0] = 1;//初始化边界
double ans = 0;
for(int i=0;i<=d;i++) {
for(int j=0;j<=n;j++) {
if(j == u) continue;
double p = 1.0/g[j].size();
for(int k=0;k<g[j].size();k++) {
int v = g[j][k];
dp[i+1][v] += (dp[i][j] * p); //在第i+1步经过v点的概率。
}
}
ans += dp[i+1][u]; //各步经过u点的概率
}
return 1.0 - ans;
}
int main() {
scanf("%d",&T);
while(T--) {
init();
for(int i=1;i<=n;i++) g[0].push_back(i);//初始化边界
for(int i=1;i<=n;i++) {
printf("%.10lf\n",solve(i));
}
}
return 0;
}