POJ 3156 HASH 期望DP

/*
DP方面是很好理解的,正常的期望DP用记忆化搜索处理

关键是怎么表示连通块的状态

首先连通快内部情况对题目解决无关重要,只需要连通快的点的个数就可以
于是我们先把每个连通快抽象成一个个具有权重的点
然后用字符串的最小表示法存储点序列
在此基础上使用HASH表示整个序列状态,主要用于记忆化搜索的时候判定是否出现过答案
如果状态出现过,则返回相应值
如果未出现过,在在原数组上再次进行DP

注意此处,由于HASH的不可逆,所以DP时依然是已原数组为基础
HASH只用于判定答案是否出现过。

*/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
const int MAXN = 33;
const unsigned int SEED = 131;  ///好像是什么magic number,记吧
map<unsigned int, double>mm;
struct Node
{
    int a[MAXN];
    Node(){memset(a, 0, sizeof a);}
    void ssort(){sort(a, a + MAXN);}
    unsigned int gethash(){
        unsigned int temp = 0;
        for(int i = MAXN - 1 ; a[i] ; i--) {
            temp = temp * SEED + a[i];
        }
        return temp;
    }
};
int fa[MAXN];
int FindFa(int u) {return fa[u] == u ? u : fa[u] = FindFa(fa[u]);}
void combine(int u, int v){int t1 = FindFa(u); int t2 = FindFa(v); if(t1 != t2) fa[t1] = t2;}
int cnt[MAXN];
int n, m;
double DP(Node node)
{
    unsigned tmp = node.gethash();
    if(tmp == n) return 0;
    if(mm[tmp]) return mm[tmp];
    double c1 = 0;
    for(int i = MAXN - 1 ; node.a[i] ; i--) c1 = c1 + (node.a[i] - 1) * node.a[i] / (1.0 * n * (n - 1));
    double c2 = 0;
    for(int i = MAXN - 1 ; node.a[i] ; i--) {
        for(int j = i - 1 ; node.a[j] ; j--) {
            Node temp;
            for(int k = 0 ; k < MAXN ; k++) temp.a[k] = node.a[k];
            temp.a[i] = temp.a[i] + temp.a[j];
            temp.a[j] = 0;
            temp.ssort();
            c2 += node.a[i] * node.a[j] * DP(temp) / (1.0 * n * (n - 1) / 2);
        }
    }
    double ans = (c2 + 1) / (1 - c1);
    mm[tmp] = ans;
    return ans;
}
int main()
{
    while(scanf("%d%d", &n, &m) != EOF) {
        mm.clear();
        for(int i = 1 ; i <= n ; i++) fa[i] = i, cnt[i] = 0;
        for(int i = 0 ; i < m ; i++) {
            int u, v;   scanf("%d%d", &u, &v);
            combine(u, v);
        }
        for(int i = 1 ; i <= n ; i++) {
            cnt[FindFa(i)]++;
        }
        Node tmp;
        for(int i = 1 ; i <= n ; i++) tmp.a[i] = cnt[i];
        tmp.ssort();
        printf("%.6f\n", DP(tmp));
    }
    return 0;
}

你可能感兴趣的:(POJ 3156 HASH 期望DP)