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

此题可以用概率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. 在XP下基于VHD版XP 2003 win7制作的RAMOS心得

    在XP下基于VHD版win7制作的RAMOS心得1.用DiskGenius创建1.85G的VHD固定磁盘文件,以win7prosen.vhd为例,然后进行分区格式化,格式化时启用NTFS压缩.2.为了 ...

  2. js用ajax和jison在不同页面的php和html之间互相传值的方法

    <script> ;//这个id必须有,如果是空值,无法实现交互.有点郁闷.... var json; $.ajax({ url:"../member/wenzhanglishi ...

  3. stream流批量读取并合并文件

    import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.F ...

  4. 关于GET请求带Body的问题

    今天在进行接口联调时遇到这个问题了,当时是很茫然的,因为从来没遇过. 后来又搜索了一下GET和Post的区别. 然后看见了这篇文章.不再以讹传讹,GET和POST的真正区别 我有限的知识还是无法去确定 ...

  5. 在excel单元格中提取信息

    平时在excel中处理数据的时候,肯定会遇到在单元格提取信息的情况,比如在地址中提取省.市.地区等,如果数据源内容规整的话,可以直接使用left().right().mid()等函数直接提取,但是大多 ...

  6. VBA对象模型(1)

    关于对象和集合的比喻 Excel的基本单元是Workbook对象:在快餐连锁店中,基本的单元是单个餐馆.使用Excel可以添加工作簿和关闭工作簿,所有打开的工作簿组成了Workbooks集合(Work ...

  7. JavaScript实现冒泡排序

    思想:从第一个元素开始,对数组中两两相邻的元素比较,将值较小的元素放在前面,值较大的元素放在后面,一轮比较完毕,一个最大的数沉底成为数组中的最后一个元素,一些较小的数如同气泡一样上浮一个位置.n个数, ...

  8. android之merge布局

    <merge />标签闪亮登场了.当LayoutInflater遇到这个标签时,它会跳过它,并将<merge />内的元素添加到<merge />的父元素里. 用& ...

  9. SpringMvc之handler深入AbstractControllerhe和MultiActionController和内部资源视图解析器

    AbstractControllerhe 若处理器继承自AbstractController类,那么该控制器就具有了一些新功能.因为AbstractController类还继承自一个父类WebCont ...

  10. Nginx+Php-fpm+MySQL+Redis源代码编译安装指南

    说明:本教程主要包括以下三个部分: 1. 源代码编译安装Nginx 2. 源代码编译安装php以及mysql.redis扩展模块 3. 配置虚拟主机 文中所涉及安装包程序均提供下载链接,欢迎使用 运行 ...