●Joyoi Dotp 驱逐猪猡

题链:

http://www.joyoi.cn/problem/tyvj-2610
题解:

期望dp,高斯消元

对于每一种到达i点的方案,都存在一个概率p,
令dp[i]表示到达i点的期望次数,那么容易由期望的定义得出:
dp[i]=p1*1+p2*1+p3*1+......(每个概率对应的权值都为1)

如果我们知道了每个点的期望的到达次数,那么在该点期望的爆炸次数=期望的到达次数*P/Q
就可以求出一个SUM=dp[1]+dp[2]+...+dp[N]
然后每个点的爆炸的概率就是(dp[i]*P/Q)/(SUM*P/Q)=dp[i]/SUM
(因为期望的权值都为1,所以概率的比例就等于期望的比例)

这种解法,更容易理解。
http://blog.csdn.net/neither_nor/article/details/52292240
如果在每个点爆炸的概率不同的话,那应该只能像这个拆点的方法做了。

没有SPJ,输出9位小数才能过2333


代码:

 

#include<bits/stdc++.h>
#define MAXN 305
using namespace std;
const double eps=1e-8;
struct Edge{
	int ent;
	int to[MAXN*MAXN*2],nxt[MAXN*MAXN*2],head[MAXN];
	Edge():ent(2){}
	void Adde(int u,int v){
		to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; nxt[ent]=head[v]; head[v]=ent++;
	}
}E;
double a[MAXN][MAXN],dp[MAXN],K,SUM;
double *A[MAXN];
int cnt[MAXN];
int N,M,P,Q;
int dcmp(double x){
	if(fabs(x)<eps) return 0;
	return x>0?1:-1;
}
void buildequation(){
	for(int i=1;i<=N;i++){
		a[i][i]=-1;
		if(i==1) a[i][N+1]=-1;
		for(int e=E.head[i];e;e=E.nxt[e]){
			int j=E.to[e];
			a[i][j]=K*1.0/cnt[j];
		}
	}
	for(int i=1;i<=N;i++) A[i]=a[i];
}
void Gausselimination(int pos,int i){
	if(pos==N+1||i==N+1) return;
	for(int j=pos;j<=N;j++) if(dcmp(A[pos][i])!=0){
		swap(A[j],A[pos]); break;
	}
	if(dcmp(A[pos][i])!=0)
		for(int j=pos+1;j<=N;j++){
			double k=A[j][i]/A[pos][i];
			for(int l=i;l<=N+1;l++)
				A[j][l]-=k*A[pos][l];
		}
	Gausselimination(pos+(dcmp(A[pos][i])!=0),i+1);
	if(dcmp(A[pos][i])!=0){
		for(int l=i+1;l<=N;l++)
			dp[i]+=A[pos][l]*dp[l];
		dp[i]=A[pos][N+1]-dp[i];
		dp[i]=dp[i]/A[pos][i];
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin>>N>>M>>P>>Q;
	K=(1-1.0*P/Q);
	for(int i=1,u,v;i<=M;i++)
		cin>>u>>v,E.Adde(u,v),
		cnt[u]++,cnt[v]++;
	buildequation();
	Gausselimination(1,1);
	for(int i=1;i<=N;i++) SUM+=dp[i];
	cout<<fixed<<setprecision(9);
	for(int i=1;i<=N;i++) cout<<fabs(dp[i]/SUM)<<endl;
	return 0;
}

 

  

 

posted @ 2018-03-11 08:38  *ZJ  阅读(164)  评论(0编辑  收藏  举报