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个顶点编号1到n,m条双向边,以及走d步,一开始随机在n个点中选择一个作为起点,然后在图中走d步,一个顶点向其每个临接点走的可能性相等,一个顶点可以多次到达,要求在所有的路径中不经过点i的概率(1<=i<=n)。
比赛时用bfs,dfs写了好长时间,还是没弄出来,就是不清楚状态怎么保存,到底是加还是乘,每条路径怎么记录。。。愣是没想到用dp[][]数组来做,哎。。。
状态用dp[i][j]保存,定义dp[i][j]为第j步到达第i个点的概率。
要求不经过第i个点的概率,也就是求到达其它点的概率,QQ群里面大神们讨论的“删点” (现在才明白T T)。怎么样才能保证不经过第i个点呢,首先起点不能从第i个点出发,其次,当一个点向其临接点转移时,不能到达第i个点。最后把dp[ j ] [ d ] , (j!=i)加起来就是所求。仔细一想,其实第二条没有什么影响,当前点j向其临接点转移的时候,到达每个点的概率是 1.0/g[j].size() (vector<int>g[52],临接表),就算到达第i个点,也不影响到达其它临接点的概率,而且最后相加的时候也和dp[i][]没关系。
代码:
#include <iostream> #include <stdio.h> #include <vector> #include <string.h> #include <algorithm> #include <iomanip> using namespace std; double dp[51][10010];//dp[i][j]代表第j步到达第i个点的概率 vector<int>g[51];//邻接表 double ans; int n,m,d; void clr() { for(int i=1;i<=n;i++) g[i].clear(); } int main() { int t; scanf("%d",&t); while(t--) { clr(); scanf("%d%d%d",&n,&m,&d); int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); g[from].push_back(to); g[to].push_back(from); } for(int i=1;i<=n;i++)//枚举每个点 { ans=0; memset(dp,0,sizeof(dp)); for(int j=1;j<=n;j++) dp[j][0]=1.0/n; for(int j=1;j<=d;j++)//枚举步数 { for(from=1;from<=n;from++)//从哪里开始走 { if(from==i) continue; for(int k=0;k<g[from].size();k++)//到哪里去 if(g[from][k]!=i)//其实不加这一句也没有影响,因为就算下一步到达的点中有i,到达其他的点的概率也是1.0/g[from].size() dp[g[from][k]][j]+=dp[from][j-1]*(1.0/g[from].size()); } } for(int j=1;j<=n;j++) if(j!=i) ans+=dp[j][d];//ans为经过除第i个点以外其他点的概率,也就是不经过第i个点的概率 cout<<setiosflags(ios::fixed)<<setprecision(10)<<ans<<endl; } } return 0; }
代码:
#include <iostream> #include <vector> #include <string.h> #include <iomanip> #include <stdio.h> using namespace std; const int maxn=51; double dp[maxn][10002]; vector<int>g[maxn]; int t,n,m,d; int main() { scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&d); for(int i=0;i<=n;i++) g[i].clear(); int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); g[from].push_back(to); g[to].push_back(from); } for(int i=1;i<=n;i++) g[0].push_back(i); for(int i=1;i<=n;i++)//枚举每个点 { memset(dp,0,sizeof(dp)); double ans=0.0; for(int j=1;j<=n;j++) dp[j][0]=1.0/n; for(int j=1;j<=d;j++)//走多少步 { for(from=0;from<=n;from++)//从哪里开始走 { if(from==i)//不从枚举的当前点开始走 continue; for(to=0;to<g[from].size();to++)//到哪里去 { dp[g[from][to]][j]+=dp[from][j-1]*1.0/g[from].size(); } } ans+=dp[i][j]; } cout<<setiosflags(ios::fixed)<<setprecision(10)<<1-ans<<endl; } } return 0; }
原文地址:http://blog.csdn.net/sr_19930829/article/details/39345213