[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.

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.

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.

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;
}
时间: 2024-12-21 03:02:32

[ACM] hdu 5001 Walk (概率DP)的相关文章

Hdu 5001 Walk 概率dp

Walk Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5001 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 bid

hdu 5001 walk 概率dp入门题

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 t

hdu 5001 Walk(概率)

http://acm.hdu.edu.cn/showproblem.php?pid=5001 应该算是一道简单的概率题.想了两个多小时,结果越想越麻烦.开了一个三维数组,MLE了.. 最后借鉴实验室学长的思路,发现这样想很直观,正退就可以. 设dp[j][d]表示不能经过i点走了d步到达j点的概率.那么dp[j][d] = ∑ dp[k][d-1]/edge[k].size().那么不经过i点的概率为∑dp[j][D]. #include <stdio.h> #include <iost

HDU 5001 Walk(鞍山网络赛E题)

HDU 5001 Walk 题目链接 思路:枚举每个要经过的点,然后进行状态转移,状态为dp[i][j],状态表示当前在j的点,已经走了i步,每次转移的时候,不从这个枚举的点出发,这样就可以求出所有路径经过该点的概率p, 然后1 - p就是不经过的答案 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; con

[ACM] hdu 3555 Bomb (数位DP,统计1-N中含有“49”的总数)

Bomb Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 7187 Accepted Submission(s): 2512 Problem Description The counter-terrorists found a time bomb in the dust. But this time the terrorists impro

[ACM] POJ 3071 Football (概率DP)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2875   Accepted: 1462 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

hdu 4870 Rating(概率DP&amp;高数消元)

Rating Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 714    Accepted Submission(s): 452 Special Judge Problem Description A little girl loves programming competition very much. Recently, she

HDU 4035Maze(概率DP)

HDU 4035   Maze 体会到了状态转移,化简方程的重要性 题解转自http://blog.csdn.net/morgan_xww/article/details/6776947 /** dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点1处(概率为ki) 2.找到出口,走出迷宫 (概率为ei) 3.和该点相连有m条边,随机走一条 求:走出迷宫所要走的边数的期望值. 设 E[i]表示

HDU 5001 Walk 求从任意点出发任意走不经过某个点的概率 概率dp 2014 ACM/ICPC Asia Regional Anshan Online

题意: 给定n个点m条边的无向图 问: 从任意点出发任意走d步,从不经过某个点的概率 dp[i][j]表示从不经过i点的前提下,走了d步到达j点的概率. #include <iostream> #include <cstdio> #include <string.h> #include <queue> #include <vector> #include <algorithm> #include <set> using n