高斯消元配合概率dp-图上随机游走模型

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目1:[HNOI2013]游走
题目大意

给你一张无向连通图,从第 1 1 1点随机游走到 n n n点。花费为经过的边的编号的和.问你如何安排边的编号使得期望花费最小化.

n ≤ 500 , m ≤ n 2 n \leq 500,m \leq n^2 n500,mn2

题目思路:

很容易想到,求出每条边期望经过次数,然后贪心安放即可.

但是 m m m太大,无法求解.考虑先求每个点期望经过次数.

考虑到 n n n点就停止了,所以不考虑 n n n的贡献。
显然有转移:
f 1 = 1 + ∑ ( 1 , j ) ∈ E f j d u j f_1=1+\sum_{(1,j)\in E}^{}\frac{f_j}{du_j} f1=1+(1,j)Edujfj
f n = 0 f_n=0 fn=0
f i = ∑ ( i , j ) ∈ E f j d u j ,   i ∈ [ 2 , n ) f_i=\sum_{(i,j)\in E}^{}\frac{f_j}{du_j}, \ i \in [2,n) fi=(i,j)Edujfj, i[2,n)

对于一条边 ( i , j ) (i,j) (i,j),它期望经过的次数是:

g i , j = f i d u i + f j d u j g_{i,j}=\frac{f_i}{du_i} + \frac{f_j}{du_j} gi,j=duifi+dujfj

所以跑高斯消元后,对边排序计算即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define mp make_pair
const int maxn = 505;
const double eps = 1e-8;
vector<int> e[maxn];
int du[maxn];
double a[maxn][maxn];
double res[maxn] , ans[maxn * maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n , m; cin >> n >> m;
    for (int i = 1 ; i <= m ; i++){
        int x , y; cin >> x >> y;
        e[x].pb(y);
        e[y].pb(x);
        du[x]++;
        du[y]++;
    }
    for (int i = 1 ; i <= n ; i++) a[i][i] = 1;
    for (int i = 1 ; i < n ; i++){
        for (auto v : e[i]){
            a[i][v] = -1.0 / du[v];
        }
    }
    a[1][n + 1] = 1;
    // guess消元
    int r , c;
    for (r = c = 1 ; r <= n && c <= n ; r++ , c++){
        int p = r;
        for (int j = r + 1 ; j <= n ; j++){
            if (a[p][c] < a[j][c]){
                p = j;
                break;
            }
        }
        // 不会有自由元
        swap(a[p] , a[r]);
        for (int j = 1 ; j <= n ; j++){
            if (j == r) continue;
            if (fabs(a[r][c]) < eps) continue;
            double d = a[j][c] / a[r][c];
            for (int k = c ; k <= n + 1 ; k++)
                a[j][k] -= d * a[r][k];
        }
    }
    for (int i = 1 ; i <= n ; i++) res[i] = a[i][n + 1] / a[i][i];
    int cnt = 0;
    for (int i = 1 ; i <= n ; i++){
        for (auto v : e[i]){
            if (v < i) continue;
            ans[++cnt] = res[i] / du[i] + res[v] / du[v];
        }
    }
    sort(ans + 1 , ans + 1 + cnt);
    double gg = 0;
   // cout << "cnt = " << cnt << endl;
    for (int i = 1 ; i <= cnt ; i++){
        gg += (cnt - i + 1.0) * ans[i];
    }
    cout << fixed << setprecision(3);
    cout << gg << endl;
    return 0;
}
题目2:bzoj3270-博物馆
题目大意:

给出一个无向图,两个人初始在两个点上。当一个人在一个点i上的时候,每一次,他有 p [ i ] p[i] p[i]的概率留在原位,有 1 − p [ i ] 1−p[i] 1p[i]的概率等概率地选择直接连边的一个点走出去。当两个人在同一时刻走到同一个点,那么他们相遇,过程结束。现在求他们在每一个点相遇的概率。

题目思路:

跟题目1没本质区别,就是升维了。令 f ( i , j ) f(i,j) f(i,j)代表两个人从最开始到站在 i , j i,j i,j期望次数,然后大力转移即可.

题目3:2019HNCPC-H-有向图
题目大意:

给你一张图。 n + m n+m n+m个点。从1点开始随机游走。有一个概率矩阵 P i , j P_{i,j} Pi,j代表从 i 到 j i到j ij的概率.后 m m m个点走到后则只会原地踏步.问你无限次之后停在后m个点的概率.

题目思路:

E ( i ) E(i) E(i)为无限次之后经过 i i i点的期望次数。由于到 i ,   i ∈ [ n + 1 , n + m ] i ,\ i \in[n+1,n +m] i, i[n+1,n+m]后就会停止。所以求解出来的期望就是概率。

转移和上述问题无差别,列方程高斯消元即可.

题目4:HDU5955-AC自动机+概率dp+高斯消元
题目大意:

n个人,每个人有一个长度为 L L L的字符串。你随机生成字符串无限次直到最后 L L L个字符串为某个人的字符串.问每个人的概率.

题目思路:

建Tire图。在Tire图上跑概率dp.然后高斯消元即可.

问题结构和题目3一模一样。我们可以直接求期望,然后概率=期望.

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值