题意:n个点(1~n),m条边,走k次,双向边,每次随机走一条路,起点也随机,问不走到各个点的概率是多少。
思路:
概率dp[i][j][k] 前i步 走到j 走不到k的概率。
那么状态转移就是 j能走到的点,传递所有dp[i][j][k]的值乘上概率。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"stack"
#include"algorithm"
#include"iostream"
#include"vector"
using namespace std;
#define N 300000
double dp[3][55][55]; //因为内存问题 用滚动数组
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m,d;
scanf("%d%d%d",&n,&m,&d);
vector<int>edge[55];
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
memset(dp,0,sizeof(dp));
int i,j,k,l;
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
if(j!=i) dp[0][i][j]+=1.0/n; //初始化,就是因为起点在i所以走不到j的概率都是n分之1
}
}
for(i=1; i<=d; i++)
{
memset(dp[i%2],0,sizeof(dp[i%2]));
for(j=1; j<=n; j++)
{
for(k=0; k<(int)edge[j].size(); k++)
{
for(l=1; l<=n; l++)
{
if(j!=l&&j!=edge[j][k]) dp[i%2][edge[j][k]][l]+=dp[1-i%2][j][l]*1.0/edge[j].size();
}
}
}
}
double ans[55];
memset(ans,0,sizeof(ans));
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
if(i!=j) ans[i]+=dp[d%2][j][i];
}
for(i=1; i<=n; i++)
printf("%.10f\n",ans[i]);
}
return 0;
}