码迷,mamicode.com
首页 > 其他好文 > 详细

[ACM] hdu 5001 Walk (概率DP)

时间:2014-09-17 18:44:22      阅读:385      评论:0      收藏:0      [点我收藏+]

标签:acm   概率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


解题思路:

题意为图中有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)

标签:acm   概率dp   

原文地址:http://blog.csdn.net/sr_19930829/article/details/39345213

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!