首页 > 代码库 > [ACM] hdu 5001 Walk (概率DP)
[ACM] hdu 5001 Walk (概率DP)
Walk
Problem Description
I used to think I could be anything, but now I know that I couldn‘t do anything. So I started traveling.
The nation looks like a connected bidirectional graph, and I am randomly walking on it. It means when I am at node i, I will travel to an adjacent node with the same probability in the next step. I will pick up the start node randomly (each node in the graph has the same probability.), and travel for d steps, noting that I may go through some nodes multiple times.
If I miss some sights at a node, it will make me unhappy. So I wonder for each node, what is the probability that my path doesn‘t contain it.
The nation looks like a connected bidirectional graph, and I am randomly walking on it. It means when I am at node i, I will travel to an adjacent node with the same probability in the next step. I will pick up the start node randomly (each node in the graph has the same probability.), and travel for d steps, noting that I may go through some nodes multiple times.
If I miss some sights at a node, it will make me unhappy. So I wonder for each node, what is the probability that my path doesn‘t contain it.
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains 3 integers n, m and d, denoting the number of vertices, the number of edges and the number of steps respectively. Then m lines follows, each containing two integers a and b, denoting there is an edge between node a and node b.
T<=20, n<=50, n-1<=m<=n*(n-1)/2, 1<=d<=10000. There is no self-loops or multiple edges in the graph, and the graph is connected. The nodes are indexed from 1.
For each test case, the first line contains 3 integers n, m and d, denoting the number of vertices, the number of edges and the number of steps respectively. Then m lines follows, each containing two integers a and b, denoting there is an edge between node a and node b.
T<=20, n<=50, n-1<=m<=n*(n-1)/2, 1<=d<=10000. There is no self-loops or multiple edges in the graph, and the graph is connected. The nodes are indexed from 1.
Output
For each test cases, output n lines, the i-th line containing the desired probability for the i-th node.
Your answer will be accepted if its absolute error doesn‘t exceed 1e-5.
Your answer will be accepted if its absolute error doesn‘t exceed 1e-5.
Sample Input
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
Sample Output
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
Source
2014 ACM/ICPC Asia Regional Anshan Online
题意为图中有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; }
一开始写的一份代码是求经过第i点的概率,最后1减去它即为所求,可是样例都通不过。。求指导。
代码:
#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; }
[ACM] hdu 5001 Walk (概率DP)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。