第一次做概率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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-11 12:47:20