题意:给一个图,有些点之间已经连边,现在给每对点之间加边的概率是相同的,问使得整个图连通,加边条数的期望是多少。

此题可以用概率DP+并查集+hash来做。

用dp(i,j,k...)表示当前的每个联通分量的点数分别是i,j,k...(连通分量的个数不固定)时,加边的期望。

这样以dp(i,j,k)为例分析状态转移的过程,dp(i,j,k)=p1*dp(i,j,k)+p2*dp(i+j,k)+p3*dp(i,j+k)+p4*dp(j,i+k)+1。

终止条件是dp(n)=0,因为此时图一定联通,所以期望是0。

这个式子是怎么来的呢?

p1*dp(i,j,k)表示增加了一条边之后原来的联通分量没有改变时的情况,p1表示选中这样的无用边的概率;p2*dp(i+j,k)表示增加了一条连结i和j这两个联通分量的边,p2表示选中i和j之间的边的概率。最后的1表示增加了一条边。

这里我们要计算选边概率。

首先有n*(n-1)/2条边。

如果选中了不改变图的联通分量的边,此时说明每次加的边都属于一个连通分量,所以一共有sum{(cnt(i)*cnt(i)-1)/2}(cnt(i)表示该联通分量内有cnt(i)个点)种选择情况。

如果选中了某条边连结了某两个联通分量i、j,这个时候一共有cnt(i)*cnt(j)种情况。

计算概率只需要除以边的总数即可。

计算连通分量可以用并查集。

因为这个题只看图的连通情况不在乎具体是哪个点,因此可以对每个联通分量的点数排序,使得每个状态唯一,这样可以得到很多重叠的子问题,整个问题就可以用记忆化搜索完成了。

很明显问题的状态比较复杂,直接下手很难处理也容易超时,所以用hash处理状态压缩判重。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define MOD 100007
using namespace std;
int n,m;
struct State
{
    double val;
    ];
    bool vis;
    State()
    {
        memset(x,,sizeof(x));
        vis=false;
    }
    void clear()
    {
        memset(x,,sizeof(x));
        vis=false;
    }
    void mysort()
    {
        sort(x,x+);
    }
    int myhash() const
    {
        ;
        ,b=; i>=&&x[i]; --i)
        {
            res+=x[i]*b;
            res%=MOD;
            b*=;
            b%=MOD;
        }
        return res;
    }
    bool operator ==(State &t)const
    {
        ; i<; ++i) if(x[i]!=t.x[i]) return false;
        return true;
    }
    bool operator !=(State &t) const
    {
        return !(*this==t);
    }
};
State has[MOD+],st;
void inserthash(State &p)
{
    int v=p.myhash();
    while(has[v].vis)
        ;
    has[v]=p;
    has[v].vis=true;
}
double gethash(State &p)
{
    int v=p.myhash();
    while(has[v].vis&&has[v]!=p)
        ;
    ;
}
];
int find(int p)
{
    return p==father[p]?p:(father[p]=find(father[p]));
}
void init()
{
    ; i<=n; ++i) father[i]=i;
    st.clear();
}
double DP(State &s)
{
    ;
    double v=gethash(s);
    if(v!=-1.0) return v;
    ,sn=n*(n-)/2.0;;
    ; i>=&&s.x[i]; --i)
        q+=s.x[i]*(s.x[i]-)/2.0;
    double &res=s.val;
    res=;
    ; i>=&&s.x[i]; --i)
        ; j>=&&s.x[j]; --j)
        {
            double p=s.x[i]*s.x[j]/sn;
            State t;
            ; k>=; --k)
                if(k!=i&&k!=j) t.x[k]=s.x[k];
                else if(k==i)  t.x[k]=s.x[i]+s.x[j];
                ;
            t.mysort();
            res+=p*DP(t);
        }
    res=res/(-q/sn);
    inserthash(s);
    return res;
}
];
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        ; i<m; ++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int fx=find(x),fy=find(y);
            if(fx!=fy) father[fx]=fy;
        }
        memset(cnt,,sizeof(cnt));
        ; i<=n; ++i)
            cnt[find(i)]++;
        ; i<=n; ++i)
            st.x[i-]=cnt[i];
        st.mysort();
        printf("%.6f\n",DP(st));
    }
    ;
}

学习了http://www.cnblogs.com/swm8023/archive/2012/09/21/2696593.html

POJ 3156 - Interconnect (概率DP+hash)的更多相关文章

  1. poj 1322 Chocolate (概率dp)

    ///有c种不同颜色的巧克力.一个个的取.当发现有同样的颜色的就吃掉.去了n个后.到最后还剩m个的概率 ///dp[i][j]表示取了i个还剩j个的概率 ///当m+n为奇时,概率为0 # inclu ...

  2. POJ 3071 Football(概率DP)

    题目链接 不1Y都对不住看过那么多年的球.dp[i][j]表示i队进入第j轮的概率,此题用0-1<<n表示非常方便. #include <cstdio> #include &l ...

  3. Scout YYF I POJ - 3744(概率dp)

    Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into th ...

  4. POJ - 2151 (概率dp)

    题意:有T个队伍,有M道题,要求每个队至少有一道题,并且有队伍至少过N道题的概率. 这个题解主要讲一下,后面的,至少有一道题解决和至少一道题至N-1道题解决,到底怎么算的,其实,很简单,就是母函数. ...

  5. poj 3071 Football (概率DP水题)

    G - Football Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit ...

  6. POJ 1202 Family 概率,DP,高精 难度:2

    http://poj.org/problem?id=1202 难度集中在输出格式上,因为输出格式所以是高精度 递推式: 血缘肯定只有从双亲传到儿子的,所以,设f,m为双亲,son为儿子,p[i][j] ...

  7. poj 3071 Football(概率dp)

    id=3071">http://poj.org/problem? id=3071 大致题意:有2^n个足球队分成n组打比赛.给出一个矩阵a[][],a[i][j]表示i队赢得j队的概率 ...

  8. 【POJ】2151:Check the difficulty of problems【概率DP】

    Check the difficulty of problems Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8903   ...

  9. POJ 2096 Collecting Bugs (概率DP,求期望)

    Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material stu ...

随机推荐

  1. 为什么MB51本位币金额和采购订单历史本位币金额不一样?

    翻译 为什么物料凭证的本位币金额有时和采购订单历史记录物料的本位币金额不一致? 回答: 有2个字段对应FI存放位置.物料凭证的字段(MSEG-DMBER)是存放库存账目金额.采购订单历史(EKBE-D ...

  2. Unity3D在Windows的全屏和跨屏(双屏)方案

    方案1 unity中2个摄像机场景显示在两个显示器屏幕上(一个窗口跨屏) 1.设置场景中的两个摄像机 摄像机1 摄像机2 2.设置发布的平台及分辨率 3.全屏运行游戏,没有标题栏还可以通过-popup ...

  3. 《C#开发微信门户及应用》

    C#开发微信门户及应用(40)--使用微信JSAPI实现微信支付功能 C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能 C#开发微信门户及应用(38)--微信摇一摇红包功能 C#开发 ...

  4. 高性能Web服务端 PHP vs Node.js vs Nginx-Lua 的对比分析

    1. ngx_lua nodejs php 比较 我在研究一阵子ngx_lua之后发现lua语法和js真的很像,同时ngx_lua模型也是单线程的异步的事件驱动的,工作原理和nodejs相同,代码甚至 ...

  5. js字符串函数之substring() substr()

    substring 方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置,从零开始的索引 参数     描述start     必需.一个非负的整 ...

  6. XPath语法 在C#中使用XPath示例 【转http://www.cnblogs.com/yukaizhao/archive/2011/07/25/xpath.html】非常详细的文章

    XPath语法 在C#中使用XPath示例   XPath可以快速定位到Xml中的节点或者属性.XPath语法很简单,但是强大够用,它也是使用xslt的基础知识. 示例Xml: <?xml ve ...

  7. IP的正则表达式

    首先分析IP地址0-255: 0-9:       [0-9]或 \d表示数字 10-99:   [1-9]\d 100-199: 1/d{2} 200-249:    2[0-4]\d 250-25 ...

  8. Java中Array的常用方法

    0.创建/声明一个数组 1 2 3 String[] aArray = new String[5]; String[] bArray = {"a","b",&q ...

  9. Testin

    http://www.testin.cn/ http://news.ccidnet.com/art/66/20150416/5815927_1.html 百度百科上面的   Testin是全球最大的移 ...

  10. .NET 向SQL里写入非Text类型

    一般来说,在更新DataTable或是DataSet时,如果不采用SqlParameter,那么当输入的Sql语句出现歧义时,如字符串中含有单引号,程序就会发生错误,并且他人可以轻易地通过拼接Sql语 ...