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

题目链接:

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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值