深夜肝题。。。有害身心健康QAQ

  设f[i]为到达i的概率,d[i]为i的度数。

  因为无限久之后炸弹爆炸的概率是1,所以最后在i点爆炸的概率实际上就是f[i]/sigma(f[])

  列出方程组 f[i]=sigma(f[to]*(1-p/q)/d[to]+[i==1]*(1-p/q))

  然后就可以高斯消元了

  高斯消元的方法:自己的那一位是1,to的每一位上为-(1-p/q)/d[to],n+1位上为0,这样就相当于x减去所有to为0。1的n+1上为1-p/q,因为炸弹还可能在自己这里不跑。

  这题实际上还有另一个思路,利用期望来计算,这里就直接贴博客了。。。

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn=310,inf=1e9;
const double eps=1e-13;
struct poi{int too,pre;}e[maxn*maxn*2];
int n,m,p,q,to,x,y,tot,d[maxn],last[maxn];
double sum,a[maxn][maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
void add(int x,int y){e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;}
void gauss()
{
    for(int i=1;i<=n;i++)
    {
        for(to=i;to<=n;to++)if(fabs(a[to][i])>eps)break;
        if(to!=i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[to][j]);
        double x=a[i][i];for(int j=1;j<=n+1;j++)a[i][j]/=x;
        for(int j=1;j<=n;j++)
        if(i!=j)
        {
            x=a[j][i];
            for(int k=1;k<=n+1;k++)
            a[j][k]-=x*a[i][k];
        }
    }
}
int main()
{
    read(n);read(m);read(p);read(q);double pro=1.0*p/q;
    for(int i=1;i<=m;i++)
    {
        read(x);read(y);
        d[x]++;d[y]++;
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
    {
        a[i][i]=1;
        for(int j=last[i];j;j=e[j].pre)
        a[i][e[j].too]-=(1-pro)/d[e[j].too];
    }
    a[1][n+1]=1-pro;
    gauss();
    for(int i=1;i<=n;i++)sum+=a[i][n+1];
    for(int i=1;i<=n;i++)printf("%.9lf\n",a[i][n+1]/sum);
    return 0;
}
View Code

相关文章: