洛谷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]$$

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


代碼

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

 

以前打錯的公式就讓他暫時存一下吧……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM