BZOJ 3534 [Sdoi2014]重建

矩阵-树定理 + 概率

挂题解呀:http://blog.csdn.net/iamzky/article/details/41317333

想了解这方面就去看论文:《生成树的计数及其应用》周冬(没有链接,不用点了)

这道题告诉我们:邻接矩阵中的的权可以不是1,而是其他权值,比如概率(感性认识,猜想算行列式的时候其实就是在把矩阵中树的边权乘起来,类似于重边就直接加在边权上从而使它乘起来翻倍?不会证明)

然后我就被精度卡了很久,后来发现别的都不管用,必须要在下文代码注释的地方那样打才能过。这样会把这一项绝对值最大的提上来。

原因:我猜是用大的放上面去消小的,大的那行乘的倍数是小/大,倍数较小,乘出来的值就较小,能够保证小的被消完之后,余下的f[j][i+1],f[j][i+2]…等项能保持较小。用小的去消大的,由于用的倍数是大/小,所以余下的项可能变得较大。然后就炸精度了(吗)。应该是个好习惯。

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 52
using namespace std;
namespace runzhe2000
{
    const double eps = 1e-7;
    int n;
    double f[N][N], pro = 1;
    double Gauss()
    {
        double det = 1;
        for(int i = 1; i < n; i++)
        {
            /*↓↓↓把绝对值最大的一行换上来↓↓↓*/
            int r = i;
            for(int j = i; j < n; j++)
                if(fabs(f[j][i]) > fabs(f[r][i])) r = j;
            if(r != i) for(int j = 1; j < n; j++) swap(f[i][j], f[r][j]);
            /*↑↑↑要不然我也不知道为什么会被卡精度↑↑↑*/  

            if(-eps < f[i][i] && f[i][i] < eps) return 0;       
            for(int j = i+1; j < n; j++)
            {
                double tmp = -f[j][i]/f[i][i];
                for(int k = i; k <= n; k++)
                    f[j][k] += tmp * f[i][k];
            }
            det *= f[i][i];
        }
        return det < 0 ? -det : det;
    }
    void main()
    {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                scanf("%lf",&f[i][j]);
                if(f[i][j] > 1-eps) f[i][j] -= eps;
                if(i < j)pro *= (1-f[i][j]);
                f[i][j] /= (1-f[i][j]);
            }
        for(int i = 1; i <= n; i++)
        {
            double sum = 0;
            for(int j = 1; j <= n; j++) sum += f[i][j];
            f[i][i] = -sum;
        }
        printf("%.8lf\n",Gauss() * pro);
    }
}
int main()
{
    runzhe2000::main();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值