• 【BZOJ3270】博物馆(概率dp,高斯消元)


    一眼看到这题发现和【HNOI2013】游走很像,于是同样的设 dp 然后用高斯消元解:

    f ( a , b ) f(a,b) f(a,b) 表示 A A A a a a 房间, B B B b b b 房间的概率, d e g u deg_u degu 表示 u u u 的度数。

    容易得到状态转移方程:

    f ( a , b ) = P a P b f ( a , b ) + ∑ ( u , a ) ( 1 − P u ) P b f ( u , b ) d e g u + ∑ ( v , b ) P a ( 1 − P v ) f ( a , v ) d e g v + ∑ ( u , a ) ∑ ( v , b ) ( 1 − P u ) ( 1 − P v ) f ( u , v ) d e g u d e g v egin{aligned} f(a,b)=&P_aP_bf(a,b)\ &+sum_{(u,a)}(1-P_u)P_bfrac{f(u,b)}{deg_u}\ &+sum_{(v,b)}P_a(1-P_v)frac{f(a,v)}{deg_v}\ &+sum_{(u,a)}sum_{(v,b)}(1-P_u)(1-P_v)frac{f(u ,v)}{deg_udeg_v} end{aligned} f(a,b)=PaPbf(a,b)+(u,a)(1Pu)Pbdeguf(u,b)+(v,b)Pa(1Pv)degvf(a,v)+(u,a)(v,b)(1Pu)(1Pv)degudegvf(u,v)

    需要注意的点:

    • f ( i , i ) f(i,i) f(i,i) 不能向其他的 f f f 转移,因为他们一相遇就停止继续走了。

    • f ( A , B ) f(A,B) f(A,B) 初始化应为 1 1 1

    最后输出 f ( i , i ) f(i,i) f(i,i) 就好了。

    代码如下:

    #include<bits/stdc++.h>
    
    #define N 25
    #define M 195
    #define get(a,b) ((a-1)*n+b)
    
    using namespace std;
    
    int n,m,A,B,deg[N];
    int cnt,head[N],to[M<<1],nxt[M<<1];
    double p[N],f[N*N][N*N],x[N*N];
    
    void adde(int u,int v)
    {
    	to[++cnt]=v;
    	nxt[cnt]=head[u];
    	head[u]=cnt;
    }
    
    void Gauss()
    {
    	for(int i=1;i<=n*n;i++)
    	{
    		int p=i;
    		for(int j=i+1;j<=n*n;j++)
    			if(fabs(f[j][i])>fabs(f[p][i])) p=j;
    		if(i!=p) swap(f[i],f[p]);
    		for(int j=i+1;j<=n*n;j++)
    		{
    			double tmp=f[j][i]/f[i][i];
    			for(int k=i;k<=n*n+1;k++) f[j][k]-=f[i][k]*tmp;
    		}
    	}
    	for(int i=n*n;i>=1;i--)
    	{
    		for(int j=i+1;j<=n*n;j++) f[i][n*n+1]-=x[j]*f[i][j];
    		x[i]=f[i][n*n+1]/f[i][i];
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&A,&B);
    	for(int i=1;i<=m;i++)
    	{
    		int u,v;
    		scanf("%d%d",&u,&v);
    		adde(u,v),adde(v,u);
    		deg[u]++,deg[v]++;
    	}
    	for(int i=1;i<=n;i++)
    		scanf("%lf",&p[i]);
    	f[get(A,B)][n*n+1]=1;
    	for(int a=1;a<=n;a++)
    	{
    		for(int b=1;b<=n;b++)
    		{
    			int tmp=get(a,b);
    			f[tmp][tmp]=1;
    			if(a!=b) f[tmp][tmp]-=p[a]*p[b];
    			for(int i=head[a];i;i=nxt[i])
    			{
    				int u=to[i];
    				if(u==b) continue;
    				f[tmp][get(u,b)]-=(1-p[u])*p[b]/deg[u];
    			}
    			for(int i=head[b];i;i=nxt[i])
    			{
    				int v=to[i];
    				if(a==v) continue;
    				f[tmp][get(a,v)]-=p[a]*(1-p[v])/deg[v];
    			}
    			for(int i=head[a];i;i=nxt[i])
    			{
    				int u=to[i];
    				for(int j=head[b];j;j=nxt[j])
    				{
    					int v=to[j];
    					if(u==v) continue;
    					f[tmp][get(u,v)]-=(1-p[u])*(1-p[v])/deg[u]/deg[v];
    				}
    			}
    		}
    	}
    	Gauss();
    	for(int i=1;i<=n;i++)
    		printf("%.6lf ",x[get(i,i)]);
    	return 0;
    }
    
  • 相关阅读:
    shell 基础进阶 *金字塔
    shell,awk两种方法写9*9乘法表
    shell脚本判断一个用户是否登录成功
    shell 冒泡算法 解决数组排序问题
    shell 石头剪刀布
    应用shell (ssh)远程链接主机
    nmcli命令使用
    光盘yum源autofs按需挂载
    LVM扩容,删除
    LVM创建
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448650.html
Copyright © 2020-2023  润新知