首页 > 代码库 > poj 5001 Walk &&2014 ACM/ICPC Asia Regional Anshan Online 1005(dp)

poj 5001 Walk &&2014 ACM/ICPC Asia Regional Anshan Online 1005(dp)

http://acm.hdu.edu.cn/showproblem.php?pid=5001

思路:dp计算出途径每个点的总概率,1-x即为所求解。

dp题,先介绍下dp[i][j]为第j步走在第i个点的概率,那么dp[i][j]=dp[x1][j-1]+dp[x2][j-1]+...,x1,x2为i 的相邻节点。上一步在相邻节点这一步才能走到该点嘛。

每个点概率要一个一个的算,当算到第ii个点时(没打错,ii个点与代码对应),从起点推起,起点嘛,算是第0步吧,每个点被选中几率1.0/n,直接计入ans,并将该状态记零,因为此部分概率已计入总概率,不用产生后继状态,防止重复计数。然后以每一步为一层,更新每个节点的概率,碰到所求的点ii 时将概率计入总数并该状态记零,同上,避免状态重复计算。如此即可。

代码(g++ %f不过,c++ %f %lf 都过,知道的同学路过请求告知):

#include<iostream>
#include<map>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int maxn=55;
const int maxm=3000;

int first[maxn],v[maxm],nex[maxm],out[maxn];
double dp[55][10005];
int ecnt;

void add_(int a,int b)
{
    out[a]++;
    v[ecnt]=b;
    nex[ecnt]=first[a];
    first[a]=ecnt++;
}
int main()
{
    int T,n,m,k,a,b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        ecnt=0;
        memset(out,0,sizeof out);
        memset(first,-1,sizeof first);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            add_(a,b);add_(b,a);
        }
        for(int j=1;j<=n;j++)dp[j][0]=1.0/n;
        for(int ii=1;ii<=n;ii++)
        {
            double ans=1.0/n;
            dp[ii][0]=0;
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    dp[j][i]=0;
                    for(int e=first[j];~e;e=nex[e])
                        dp[j][i]+=(dp[v[e]][i-1]/out[v[e]]);
                    if(j==ii)ans+=dp[j][i],dp[j][i]=0;
                }
            }
            dp[ii][0]=1.0/n;
            printf("%.10f\n",1-ans);
        }
    }
    return 0;
}


poj 5001 Walk &&2014 ACM/ICPC Asia Regional Anshan Online 1005(dp)