uva 1390 - Interconnect(期望+哈希+记忆化)

题目连接: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\n", solve(start));
    }
    return 0;
}

uva 1390 - Interconnect(期望+哈希+记忆化),布布扣,bubuko.com

时间: 2024-10-04 12:54:33

uva 1390 - Interconnect(期望+哈希+记忆化)的相关文章

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

uva 10626 Buying Coke (DP记忆化搜索)

uva 10626 Buying Coke I often buy Coca-Cola from the vending machine at work. Usually I buy several cokes at once, since my working mates also likes coke. A coke in the vending machine costs 8 Swedish crowns, and the machine accept crowns with the va

UVA 10003 Cutting Sticks 区间DP+记忆化搜索

UVA 10003 Cutting Sticks+区间DP 纵有疾风起 题目大意 有一个长为L的木棍,木棍中间有n个切点.每次切割的费用为当前木棍的长度.求切割木棍的最小费用 输入输出 第一行是木棍的长度L,第二行是切割点的个数n,接下来的n行是切割点在木棍上的坐标. 输出切割木棍的最小费用 前话-区间dp简单入门 区间dp的入门下面博客写的非常好,我就是看的他们博客学会的,入门简单,以后的应用就得靠自己了. https://blog.csdn.net/qq_41661809/article/d

UVA 11762 Race to 1(记忆化+期望)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20869 [思路] DP+期望. 设f[x]表示从x转移到1的期望操作次数,则有: f[x]=1+f[x]*(1-g[x]/p[x])+sigma(f[x][y])/p[x] 进一步为: f[x]=(sigma(f[x/y])+p[x])/g[x] 其中p[x]表示1..x的素数个数,p[x]表示素数中可以整除x的个数. 保留vis可以节约时间. [代码] 1 #i

UVA 1390 Interconnect

https://vjudge.net/problem/UVA-1390 题意: 给出n个点m条边的无向图, 每次随机加一条非自环的边,(加完后可出现重边), 添加每条边的概率是相等的 求使图连通的期望添边次数 只关心图的连通状况,即连通块的个数和大小 所以可以用{a1,a2,a3……an} 表示状态(n个连通块,每个连通块大小为ai) 添加一条边后有两种可能 1.状态不变 2.状态变为 {a1,……ai+aj,……a_n-1} 将状态哈希 dp[i]表示哈希后为i的状态 添边至连通的期望次数 d

UVa 10651 Pebble Solitaire(DP 记忆化搜索)

Pebble Solitaire Pebble solitaire is an interesting game. This is a game where you are given a board with an arrangement of small cavities, initially all but one occupied by a pebble each. The aim of the game is to remove as many pebbles as possible

Uva 10118 Free Candies (DP+记忆化搜索)

The Problem Little Bob is playing a game. He wants to win some candies in it - as many as possible. There are 4 piles, each pile contains N candies. Bob is given a basket which can hold at most 5 candies. Each time, he puts a candy at the top of one

UVA 11008--Antimatter Ray Clearcutting+状态压缩记忆化搜索

题目链接:点击进入 最多只有16个点,如果不用状态压缩的话,最优子结构没法找到.所以我们进行状态压缩,用一个数表示当前的状态,对应二进制位为1表示该位置的树还未被砍掉,为0表示已被砍掉,初始状态为(1< #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 20 #define INF 0x3f3f3f3f typedef struct { i

UVa 10118 Free Candies (记忆化搜索+哈希)

题意:有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果,如果篮子里有两个相同的糖果, 那么就可以把这两个(一对)糖果放进自己的口袋里,问最多能拿走多少对糖果. 析:首先看到的是时间30s,这么长时间,一想应该是暴力了吧,后来一想应该是记忆化搜索,既然这么长时间,应该得优化一下,不然可能超时, 但是数据好像挺水,才运行了60ms,并不知道是怎么回事,接下来说说这个题,用 d[a,b,c,d] 来表示 分别从 第一,二,三,四堆拿的最多糖果, 如