• POJ 3156 Interconnect [期望DP]


      给出N个点M条边,每次等概率的给这张图加一条边,求连通这个图加边次数的期望。

      这题我们并不关心图的形状,只要知道图的连通情况即可,即这张图有几个连通块,每个连通块中有几个顶点。比如,我们用E(2,3,3)表示当这个图有3个连通块,每个连通块中的顶点数分别是2,3,3时,我们把它连通所需加边的期望,对于8个顶点的图,E(8)=0。可以得到转移方程

      E(2,3,3)=p1*E(2,3,3)+p2*E(2,6)+p3*E(3,5)+1。

      把右边的第一项移到左边,然后用记忆化搜索就可以求解了。

      其中p1,p2,p3是转移到其它连通情况的概率,在8个点里连一条边,总的方案数显然是C(8,2)。如果这条边没有改变连通情况,说明连的是同一个连通块里的边,于是p1=(C(2,2)+C(3,2)+C(3,2))/C(8,2)。否则就是在两个连通块里各选了一条边,枚举可以得到p2=(3*3)/C(8,2),p3=(2*3+2*3)/C(8,2)。

      对图的每种状态先排个序,然后用HASH即可。

      

     1 #include <string.h>
     2 #include <stdio.h>
     3 #include <algorithm>
     4 #define MAXN 50
     5 #define INF 0x3f3f3f3f
     6 #define MOD 100007
     7 struct sta{
     8     int x[30],flag;
     9     double val;
    10     void clear() {memset(x, 0, sizeof x);}
    11     void sort() {std::sort(x, x + 30);}
    12     int hashme() {
    13         int v = 0;
    14         for (int i = 29, b = 1; i >= 1 && x[i]; i--)
    15             v += x[i] * b, v %= MOD, b *= 30, b %= MOD;
    16         return v;
    17     }
    18     bool operator ==(sta b) {
    19         for (int i = 0; i < 30; i++) if(x[i] != b.x[i]) return false;
    20         return true;
    21     }
    22     bool operator !=(sta b) {
    23         return *this == b ? false: true;
    24     }
    25 
    26 }st,hh[MOD];
    27 int n, m, tu, tv;
    28 int p[MAXN], tot[MAXN];
    29 int find(int x) {return x == p[x] ? x : p[x] = find(p[x]);}
    30 void inshash(sta st) {
    31     int x = st.hashme();
    32     while (hh[x].flag == 1) {
    33         if (++x == MOD) x = 0;
    34     }
    35     hh[x] = st, hh[x].flag = 1;
    36 }
    37 double gethash(sta st) {
    38     int x = st.hashme();
    39     while (hh[x].flag == 1 && hh[x] != st) {
    40         if (++x == MOD) x = 0;
    41     }
    42     return hh[x] == st ? hh[x].val : -1;
    43 }
    44 
    45 double dp(sta ost) {
    46     if(ost.hashme() == n) return 0;
    47     double x = gethash(ost);
    48     if(x != -1.0)return x;
    49     //不会改变连通的方案
    50     double tmp = 0, ans = 0;
    51     for (int i = 0; i < 30; i++)
    52         tmp += (ost.x[i] * (ost.x[i] - 1)) / 2;
    53     //会把两个非连通子图连通的方案
    54     for (int i = 0; i < 30; i++) {
    55         for (int j = i+1; j < 30; j++) {
    56             if(ost.x[i]==0||ost.x[j]==0)continue;
    57             sta stt = ost;
    58             stt.x[i] += stt.x[j], stt.x[j] = 0;
    59             stt.sort();
    60             ans += ost.x[i] * ost.x[j] * dp(stt);
    61         }
    62     }
    63     ans /= (n * (n-1) / 2), ans++;
    64     ans /= (1 - tmp / (n * (n-1) / 2));
    65     ost.val = ans;
    66     inshash(ost);
    67     return ans;
    68 }
    69 int main(){
    70     while (scanf("%d%d", &n, &m) != EOF) {
    71         for (int i = 0; i < MOD; i++) hh[i].flag = 0;
    72         for (int i = 1; i <= n; i++) p[i] = i;
    73         for (int i = 0; i < m; i++) {
    74             scanf("%d%d", &tu, &tv);
    75             p[find(tu)] = find(tv);
    76         }
    77         st.clear();
    78         int xs = 0;
    79         memset(tot, 0, sizeof tot);
    80         for (int i = 1; i <= n; i++) tot[find(i)]++;
    81         for (int i = 1; i <= n; i++) if(tot[i]) st.x[xs++] = tot[i];
    82         st.sort();
    83         printf("%.10f\n",dp(st));
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    上市前为什么要分红
    在文件开始追加一行
    c++ 日期时间工具
    windows c++找不到time.h sys/types.h
    截取ls -l的某一列
    提取指定类型文件到指定目录,保留目录结构
    批量转换当前目录下的文件名为snake case
    vcpkg boost uuid Bcrypt 链接问题
    文件名pascal转underscore
    vcpkg cmake 找不到boost
  • 原文地址:https://www.cnblogs.com/swm8023/p/2696593.html
Copyright © 2020-2023  润新知