您的位置:首页 > 其它

POJ 3156 HASH 期望DP

2016-03-16 11:30 337 查看
/*

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: