zoukankan      html  css  js  c++  java
  • [bzoj 3270] 博物馆:高斯消元+期望转移

    [bzoj 3270] 博物馆

    http://www.lydsy.com/JudgeOnline/problem.php?id=3270%20%E4%BC%A0%E9%80%81%E9%97%A8)


    乍一看比较难想到这是一道高斯消元的题目,因为概率不好转移,得不到方程。
    但是反过来想,用f(a,b)来表示,两个人分别在a房间和b房间的期望。那么这个期望是可以通过与其相连的房间的期望累加得到的:

    f[a,b]+=f[p,q]*p1

    这里的f[p,q]是枚举的出发点,而p1是其对应的概率;

    所以可以看出一个多元带有系数的方程,这才引出了高斯消元;
    需要用一个函数对 点对进行编号 code(i,j)

    特别注意的是:
    a[code(a,b)][tot+1]=-1
    a,b是初始状态,期望肯定是有一个1的,移项后得-1;

    下见代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #define EPS 0.0000000001
    #define cnt (n*n) 
    using namespace std;
    
    int n,m,a1,b,d[50],mp[50][50];
    double a[500][500],p[50];
    
    int code(int i,int j){return (i-1)*n+j;}
    
    void build(int x,int y){
        if(x==a1&&y==b)a[code(x,y)][cnt+1]=-1;
        a[code(x,y)][code(x,y)]=-1;
        for(int i=1;i<=d[x];i++)
            for(int j=1;j<=d[y];j++){
                int tx=mp[x][i],ty=mp[y][j];//tx,ty枚举的可抵达的起始点;
                if(tx==ty)continue;
                double p1,p2; 
                if(tx==x)p1=p[tx];
                else p1=(1-p[tx])/(d[tx]-1);
                if(ty==y)p2=p[ty];
                else p2=(1-p[ty])/(d[ty]-1);
                a[code(x,y)][code(tx,ty)]+=p1*p2;
            }
    } 
    
    void Gauss(){
        for(int i=1;i<=cnt;i++){
            int j=i;
            while(j<=cnt&&abs(a[j][i])<EPS)j++;
            if(j>cnt)continue;
            if(j!=i)swap(a[i],a[j]);
            for(int j=1;j<=cnt;j++)if(j!=i){
                double t=(a[j][i])/a[i][i];
                for(int k=i;k<=cnt+1;k++)
                    a[j][k]-=a[i][k]*t;
            }
        }
    }
    
    int main()
    {
    #ifdef YSW
        freopen("in.txt","r",stdin);
    #endif
        scanf("%d%d%d%d",&n,&m,&a1,&b);
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
            mp[x][++d[x]]=y;
            mp[y][++d[y]]=x;
        }
        for(int i=1;i<=n;i++)scanf("%lf",&p[i]),mp[i][++d[i]]=i;//可留在原地,所以起始点多了自己;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                build(i,j);
        Gauss();
        for(int i=1;i<=n;i++)
            printf("%.6lf ",a[code(i,i)][cnt+1]/a[code(i,i)][code(i,i)]);
        return 0; 
    }
  • 相关阅读:
    setTimeout()和setInterval()的区别
    iOS开发小技巧
    iOS应用跳转到App Store评分
    前端小技巧-定位的活学活用之仿淘宝列表
    前端CSS
    用c# 开发html5的尝试,试用bridge.net
    Faster数据库研习,一
    五一劳动节,讲讲NEO智能合约的调试
    NEO GUI 多方签名使用
    NEO智能合约开发(二)再续不可能的任务
  • 原文地址:https://www.cnblogs.com/DexterYsw/p/7136255.html
Copyright © 2011-2022 走看看