题链:
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; }