hdu 5001 Walk(概率dp+搜索,矩阵快速幂)

来源:互联网 发布:金税盘开票软件最新版 编辑:程序博客网 时间:2024/04/16 16:10

题目链接:

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

解题思路:

题目大意:

给你一张无向的连通图,一共有n个点,m条边,随机从任意一点开始走,在任意一个点走向相连的点的概率都是相同的,一共走d步,分别求出每个点不在这个路径中的概率。

算法思想:

1.枚举每个要经过的点,然后进行状态转移,状态为dp[i][j],状态表示当前在j的点,已经走了i步,每次转移的时候,不从这个枚举的点出发,这样就可以求出所有路径经过该点的概率p, 然后1 - p就是不经过的答案

2.根据题目条件求出整张图的转移矩阵。然后对于每一个求值的点,将矩阵中以该点为起点的值的置0,然后利用矩阵快速幂,求出走了d步之后在其他的点的概率之和,即该点不在路径中的概率。

AC代码(概率dp+搜索):

#include <iostream>#include <cstdio>#include <cstring>#include <vector>using namespace std;const int N = 55;const int M = 10005;int n,m,d;double dp[N][M];vector<int> v[N];double solve(int u){    double ans = 0;    memset(dp,0,sizeof(dp));    dp[0][0] = 1;    for(int i = 0; i <= d; i++){        for(int j = 0; j <= n; j++){            if(u == j)                continue;            double p = 1.0 / v[j].size();            for (int k = 0; k < v[j].size(); k++) {                dp[v[j][k]][i + 1] += dp[j][i] * p;            }        }        ans += dp[u][i + 1];    }    return 1.0 - ans;}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d%d%d",&n,&m,&d);        for(int i = 0; i <= n; i++)            v[i].clear();        int x,y;        for(int i = 0; i < m; i++){            scanf("%d%d",&x,&y);            v[x].push_back(y);            v[y].push_back(x);        }        for(int i = 1; i <= n; i++)            v[0].push_back(i);        for(int i = 1; i <= n; i++)            printf("%.10lf\n",solve(i));    }    return 0;}

AC代码(矩阵快速幂):

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;const int N = 55;vector<int> v[N];int n,m,d;struct matrix{    double num[N][N];}val;matrix mul(matrix a,matrix b){    matrix ret;    for(int i = 1; i <= n;i++){        for(int j = 1; j <= n;j++){            ret.num[i][j] = 0;            for(int k = 1;k <= n;k++)                ret.num[i][j] += a.num[i][k]*b.num[k][j];        }    }    return ret;}void solve(int n,int d,int x){//求不经过x点的概率    matrix ans,base = val;    memset(ans.num,0,sizeof(ans.num));    for(int i = 1;i <= n;i++)        ans.num[i][i] = 1;    for(int i = 1;i <= n;i++)        base.num[i][x] = 0;//对于所求点,将以该点为起点的值置0    //矩阵a次幂的结果num[i][j]表示以j为起点,走a步走到i点概率    while(d){        if(d&1)            ans = mul(ans,base);        base = mul(base,base);        d/=2;    }    double ret = 0;    for(int i = 1; i <= n; i++){        if(i == x)            continue;        for(int j = 1; j <= n; j++){            if(j == x)                continue;            ret += ans.num[i][j];//以j点为起点,不经过x点的情况下,走了d步最终走到i点的概率,求和即为所求点        }    }    printf("%.10f\n",ret/n);//矩阵快速幂求的结果默认每个起点的概率为1,实际为1/n,因此最终结果要除以n}int main(){    int T;    scanf("%d",&T);    while(T--){        int x,y;        scanf("%d%d%d",&n,&m,&d);        for(int i = 0; i <= n; i++)            v[i].clear();        for(int i = 0;i < m;i++){            scanf("%d%d",&x,&y);            v[x].push_back(y);            v[y].push_back(x);        }        memset(val.num,0,sizeof(val.num));        for(int i = 1; i <= n; i++){            int l = v[i].size();            for(int j = 0; j < l; j++){                int tmp = v[i][j];                val.num[i][tmp] = 1.0/v[tmp].size();//从tmp点走到i点的概率                val.num[tmp][i] = 1.0/v[i].size();//从i点走到tmp点的概率            }        }        for(int i=1;i<=n;i++)            solve(n,d,i);    }    return 0;}


0 0
原创粉丝点击