洛谷2973 [USACO10HOL]赶小猪Driving Out the Piggi… 概率 高斯消元

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - 洛谷2973


题意概括

  N个城市,M条双向道路组成的地图,城市标号为1到N。“西瓜炸弹”放在1号城市,保证城市1至少连接着一个其他城市。“西瓜炸弹”有P/Q的概率会爆炸,每次进入其它城市时,爆炸的概率相同。如果它没有爆炸,它会随机的选择一条道路到另一个城市去,对于当前城市所连接的每一条道路都有相同的可能性被选中。对于给定的地图,求每个城市“西瓜炸弹”爆炸的概率。


题解

  通过概率关系构建方程:

  其中in[j]表示节点j的出度,$F_i$ 表示最终在节点 $i$ 爆炸的概率。

$$F_i = \sum_{存在j到 i 的边}\cfrac{(1-\frac PQ)F_j}{in[j]}+\cfrac PQ \cdot [i=1]$$

  然后高斯消元跑一跑就可以了。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N=300+5;
const double Eps=1e-9;
int n,m,P,Q,cnt[N];
bool g[N][N];
double p,a[N][N],x[N];
void Gauss(){
    int row=n,col=n,k,c;
    for (k=c=1;k<=row,c<=col;k++,c++){
        int Mk=k;
        for (int i=k+1;i<=row;i++)
            if (fabs(a[Mk][c])<fabs(a[i][c]))
                Mk=i;
        if (fabs(a[Mk][c])<Eps){
            k--;
            continue;
        }
        if (k!=Mk)
            for (int i=c;i<=col+1;i++)
                swap(a[k][i],a[Mk][i]);
        for (int i=k+1;i<=row;i++)
            for (int j=col+1;j>=c;j--)
                a[i][j]=a[i][j]-a[k][j]*a[i][c]/a[k][c];
    }
    memset(x,0,sizeof x);
    for (int i=k;i>=1;i--){
        x[i]=a[i][n+1];
        for (int j=i+1;j<=n;j++)
            x[i]-=a[i][j]*x[j];
        x[i]/=a[i][i];
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&P,&Q);
    p=double(P)/double(Q);
    memset(g,0,sizeof g);
    memset(cnt,0,sizeof cnt);
    for (int i=1,a,b;i<=m;i++){
        scanf("%d%d",&a,&b);
        g[a][b]=g[b][a]=1;
        cnt[a]++,cnt[b]++;
    }
    memset(a,0,sizeof a);
    a[1][n+1]=p;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++){
            if (i==j){
                a[i][j]=1;
                continue;
            }
            if (!g[i][j])
                continue;
            double del=(1.0-p)/double(cnt[j]);
            a[i][j]-=del;
        }
    Gauss();
    for (int i=1;i<=n;i++)
        if (fabs(x[i])<Eps)
            x[i]=0;
    for (int i=1;i<=n;i++)
        printf("%.9lf\n",x[i]);
    return 0;
}

 

以前打错的公式就让他暂时存一下吧……

posted @   zzd233  阅读(406)  评论(9编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架

点击右上角即可分享
微信分享提示