您的位置:首页 > 编程语言 > PHP开发

bzoj1778: [Usaco2010 Hol]Dotp 驱逐猪猡(概率DP+高斯消元)

2017-08-29 00:58 537 查看

  深夜肝题。。。有害身心健康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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: