P2973 [USACO10HOL]Driving Out the Piggies G(高斯消元求期望)
https://www.luogu.com.cn/problem/P2973
题目描述:一个无向图,节点1有一个炸弹,在每个单位时间内,有p/q的概率在这个节点炸掉,有1-p/q的概率随机选择一条出去的路到其他的节点上。问最终炸弹在每个节点上爆炸的概率。
搬运洛谷的题解:https://siyuan.blog.luogu.org/solution-p2973
在dp顺序混乱的时候,就可以开始考虑转换成方程组再高斯消元。
正如上面的式子,把右边Σ的式子移到左边,就得到一个n元一次方程。
其次考虑增广列b[1~n]应该是什么。
移项后很明显b[1]=1,b[其他]=0。
代码:
#include<cstdio> // #include<iostream> // #include<deque> // #include<cstring> // #include<cmath> // #include<map> // #include<vector> // #include<stack> // #include<algorithm> // #include<queue> // #include<set> #include<bits/stdc++.h> #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define sf(x) scanf("%lf",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(register int i=a;i<=b;i++) #define fd(i,a,b) for(register int i=a;i>=b;i--) #define all(a) a.begin(),a.end() #define range(a,x,y) a+x,a+y+x #define dbug printf("bbbk\n") #define R register using namespace std; using namespace __gnu_cxx; typedef long long ll; typedef unsigned long long ull; typedef long double ld; typedef pair<ll,ll> P; const int N=300+99; const int MN=1e7+9; const ll mod=1e9+7; const int MAX=1e9; const ll INF=1e9+7; int n,m,d[N],to[N][N]; bitset<N> p[N]; double eps=1e-10; double a[N][N]; inline void guass() { int now=1; fu(i,1,n) { int p=now; fu(j,now+1,n) { if(fabs(a[j][i])>fabs(a[p][i])) p=j; } if(fabs(a[p][i])<=eps) continue; swap(a[now],a[p]); fu(j,1,n) { if(j==now) continue; if(fabs(a[j][i])<=eps) continue; double r=a[j][i]/a[now][i]; fu(k,i,n+1) a[j][k]-=a[now][k]*r; } now++; } } int main() { cin>>n>>m; double p,q;cin>>p>>q; fu(i,1,m) { int u,v;cin>>u>>v; to[u][v]=to[v][u]=1; d[v]++,d[u]++; } fu(i,1,n) { a[i][i]=1; fu(j,1,n) { if(i!=j&&to[i][j]) a[i][j]-=(1.0-p/q)/d[j];//i为爆炸点 } } a[1][n+1]=1;//增广列b[1]=1,其余b[i]=0。 guass(); fu(i,1,n) printf("%.9f\n",a[i][n+1]/a[i][i]*(p/q)); return 0; }