zoukankan      html  css  js  c++  java
  • uva 1390

    题目连接:uva 1390 - Interconnect

    题目大意:给出n表示有n个点,m表示有m条边,如今任选两点建立一条边。直到整个图联通,问说还需建立边数的期望,建过边的两点仍能够建边。

    解题思路:哈希的方法非常是巧妙。将各个联通分量中节点的个数c[i]转换成一个30进制的数(由于节点个数最多为30)。由于结果非常大。所以对1e5+7取模。获得的哈希值作为插入和搜索的起点。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 30;
    const int mod = 1e5+7;
    
    struct state {
        int c[maxn], flag;
        double val;
    
        void clear () { memset(c, 0, sizeof(c)); }
        int hash() {
            int x = 0;
            for (int i = 0; i < maxn; i++)
                x = (x * 30 + c[i]) % mod;
            return x;
        }
        bool operator == (const state& u) {
            for (int i = 0; i < maxn; i++)
                if (c[i] != u.c[i])
                    return false;
            return true;
        }
    
        bool operator != (const state& u) {
            return !(*this == u);
        }
    
    }start, ha[mod+7];
    
    int n, m, f[maxn+5], s[maxn+5];
    double dive;
    
    int getfar (int x) {
        return f[x] == x ? x : f[x] = getfar(f[x]);
    }
    
    void link (int x, int y) {
        int p = getfar(x);
        int q = getfar(y);
    
        if (p == q)
            return;
    
        f[q] = p;
        s[p] += s[q];
    }
    
    void inserthash (state u) {
        int x = u.hash();
        while (ha[x].flag) {
            if (++x == mod)
                x = 0;
        }
        ha[x] = u;
        ha[x].flag = 1;
    }
    
    double gethash (state u) {
        int x = u.hash();
        while (ha[x].flag && ha[x] != u) {
            if (++x == mod)
                x = 0;
        }
        return ha[x] == u ? ha[x].val : -1;
    }
    
    void init () {
        dive = n * (n - 1) / 2.0;
        start.clear();
        for (int i = 0; i <= n; i++) {
            s[i] = 1;
            f[i] = i;
        }
    
        for (int i = 0; i < mod; i++)
            ha[i].flag = 0;
    
        int a, b;
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &a, &b);
            link(a, b);
        }
    
        for (int i = 1; i <= n; i++) {
            if (f[i] == i)
                start.c[i-1] = s[i];
        }
    }
    
    double solve (state u) {
        sort(u.c, u.c+maxn);
        if (u.hash() == n)
            return 0;
    
        double x = gethash(u);
    
        if (x != -1.0)
            return x;
    
        double ans = 0, tmp = 0;
    
        for (int i = 0; i < maxn; i++)
            tmp += u.c[i] * (u.c[i] - 1) / 2.0;
    
        for (int i = 0; i < maxn; i++) {
    
            if (u.c[i] == 0)
                continue;
    
            for (int j = i+1; j < maxn; j++) {
    
                if (u.c[j] == 0)
                    continue;
    
                state v = u;
                v.c[i] += v.c[j];
                v.c[j] = 0;
                ans += u.c[i] * u.c[j] * solve(v);
            }
        }
    
        ans /= dive;
        ans++;
        ans /= (1 - tmp / dive);
        u.val = ans;
        inserthash(u);
        return ans;
    }
    
    int main () {
        while (scanf("%d%d", &n, &m) == 2) {
            init();
            printf("%.10lf
    ", solve(start));
        }
        return 0;
    }
  • 相关阅读:
    Delphi三层开发小技巧:TClientDataSet的Delta妙用
    Delphi ADOQuery的速度优化
    delphi ADOQUery中错误解决方法"无法为更新定位行。一些值可能已在最后...
    ClientDataSet中修改,删除,添加数据和Delta属性
    学习 SQL 语句
    Delphi处理数据网格DBGrid的编辑框 获取还没有提交到数据集的字段文本
    移动前端头部标签(HTML5 head meta)
    最全面的前端开发指南
    解决jQuery.live在mobile safari(iphone / ipad / ipod)绑定失败的问题
    jQuery滑动选取数值范围插件
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5146721.html
Copyright © 2011-2022 走看看