zoukankan      html  css  js  c++  java
  • 洛谷3317 SDOI2014重建(高斯消元+期望)

    qwq
    一开始想了个错的做法。

    直接开始说比较正确的做法吧。
    首先我们考虑题目的(ans)该怎么去求
    我们令(x)表示原图中的某一条边

    [ans = sum prod_{xin tree} p_x prod_{x notin tree} (1-p_x) ]

    qwq而根据矩阵树定理,我们可以求出来所有生成树的边权乘积的和,也就是前一部分。

    现在我们考虑应该怎么优化第二部分。
    qwq
    我们经过推理能发现,我们可以用总的除去在生成树里面的求出来不在生成树里面的。

    也就是说

    [prod_{x not in tree} (1-p_x)= frac{prod (1-p_i)}{prod_{xin tree} (1-p_j)} ]

    我们带回原柿,然后把(prod (1-p_i))提出来

    [ans = prod (1-p_x) imes sum prod_{x in tree} frac{p_x}{1-p_x} ]

    那么现在,对于后面那一项,我们只需要把所有的边都设成权值是(prod_{x in tree} frac{p_x}{1-p_x})
    然后每个(d[i])表示与他连接的所有边权的和。

    直接跑矩阵树定理就能求出来(sum)啦,然后直接用一开始求的(prod p_x),一减就OK了

    但是这里有一个需要注意的地方就是当(p_x)等于(1)的时候,我们应该将他的权值设成(1-eps)

    因为当(p)等于1的时候,(frac{1}{1-p} -> inf)

    然后有因为(frac{1}{eps}->inf)

    所以(p=1-eps)

    然后弄完权值直接跑矩阵树定理就好

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk make_pair
    #define ll long long
    #include<ctime>
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 110;
    const double eps = 1e-6;
    double a[maxn][maxn];
    double d[maxn];
    int n;
    double ans=1;
    void gauss()
    {
    	int k=1;
    	for (int i=1;i<=n;i++)
    	{
    		int now = k;
    		while(now<=n && fabs(a[now][i])<=eps)  now++;
    		if (now==n+1) continue;
    		for (int j=1;j<=n+1;j++) swap(a[now][j],a[k][j]);
    		for (int j=1;j<=n;j++)
    		{
    			if (j!=k)
    			{
    				double t = a[j][i]/a[k][i];
    				for (int p=1;p<=n+1;p++) a[j][p]-=t*a[k][p];
    			}
    		}
    		++k;
    	}
    	for (int i=1;i<=n;i++)
    	  ans=ans*a[i][i];
    }
    double ymh=1;
    int main()
    {
      n=read();
      for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
        	double x;
        	scanf("%lf",&x);
        	if (x==1) x = 1-eps;
    		if (i<j) ymh=ymh*(1-x);
        	x=x/(1-x);
        	a[i][j]=-x;
        	d[i]+=x;
        	//d[j]+=x;
    	}
      for (int i=1;i<=n;i++) a[i][i]=d[i];
      gauss();
      printf("%.5lf",ans*ymh);
      return 0;
    }
    
    
  • 相关阅读:
    (数据科学学习手札48)Scala中的函数式编程
    Java中的集合(十三) 实现Map接口的Hashtable
    Java中的集合(十二) 实现Map接口的WeakHashMap
    Java中的集合(十一) 实现Map接口的TreeMap
    Java集合(十)实现Map接口的HashMap
    Java集合(九)哈希冲突及解决哈希冲突的4种方式
    Java集合(八)哈希表及哈希函数的实现方式
    Java中的集合(七)双列集合顶层接口------Map接口架构
    Java中的集合(六)继承Collection的Set接口
    Java中的集合(五)继承Collection的List接口
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10152025.html
Copyright © 2011-2022 走看看