HDU Walk (概率DP):http://acm.hdu.edu.cn/showproblem.php?pid=5001
题面描述:
Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 996 Accepted Submission(s): 634
Special Judge
2 5 10 100 1 2 2 3 3 4 4 5 1 5 2 4 3 5 2 5 1 4 1 3 10 10 10 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 4 9
0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.6993317967 0.5864284952 0.4440860821 0.2275896991 0.4294074591 0.4851048742 0.4896018842 0.4525044250 0.3406567483 0.6421630037
题目大意:
在一个n给节点,m条边的无向图中,以每个顶点为起点的概率相等,求经过d步之后,不经过该点的概率为多少。
题目解析:
不经过这个节点的概率等于去掉该节点的图中走了d步到其他顶点的和。
特殊的枚举方式,对于每个i,因为不让他到达这个点i,所以不达到点i的概率就是到达其他顶点的概率和,不求该点即可。
代码实现:
#include <iostream> #include <cstdio> #include <vector> #include <cstring> using namespace std; #define maxn 55 #define maxstep 10005 vector<int> V[maxn]; double dp[maxstep][maxn]; int main() { int T; int n,m,d; scanf("%d",&T); while(T--) { int a,b; scanf("%d%d%d",&n,&m,&d); for( int i=1; i<=n; i++) { V[i].clear(); } for( int i=1; i<=m; i++) { scanf("%d%d",&a,&b); V[a].push_back(b); V[b].push_back(a); } for(int i=1; i<=n; i++) { dp[0][i]=1.0/n; } for(int i=1; i<=n; i++) { //memset(dp,0,sizeof(dp)); for(int j=1; j<=d; j++) { for(int k=1; k<=n; k++) { if(k==i) continue; dp[j][k]=0; for(int q=0; q<V[k].size(); q++) { if(V[k][q]==i) continue; else dp[j][k]+=dp[j-1][V[k][q]]*(1.0/V[k].size()); } } } double ans=0; for(int j=1; j<=n; j++) { if(j==i) continue; else ans+=dp[d][j]; } printf("%.10lf\n",ans); } } return 0; }