uva 11600 - Masud Rana(记忆化搜索)

题目链接:uva 11600 - Masud Rana


题目大意:给出n和m,表示说有n座城市,每两座城市间有一条路,每条路上都有怪物,现在有m条路上没有怪物,给出没有怪物的路。现在任选一座城市移过去,清除路上的怪物,当所有城市可以直接连接时终止,问说需要移动次数的期望。


解题思路:首先将已经联通的城市算成是一个联通集,这样的话,就有k个联通集,k小于三十,所以可以用二进制数来表示状态,所以有d[u][s]表示说从u这个联通即开始,已经联通的状态为s的情况下,还需要多少次的期望。转移方程:link为已经联通了的城市的数量,那么n个城市,选中未联通的可能性为(n-link)/(n-1),所以就是说有平均需要(n-1)/(n-link)次会选中为联通的城市进行移动,d[u][s] =(n-1)/(n-link) + 剩下的联通集的期望。


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;
const int N = 35;

int n, m, k, v[N], c[N];
vector<int> g[N];
map<int, double> d[N];

int dfs (int u) {
	v[u] = 1;
	int ans = 1;
	for (int i = 0; i < g[u].size(); i++) {
		if (v[g[u][i]]) continue;
		ans += dfs(g[u][i]);
	}
	return ans;
}

void init () {
	scanf("%d%d", &n, &m);

	int a, b;
	memset(v, 0, sizeof(v));
	for (int i = 1; i <= n; i++) g[i].clear();

	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		g[a].push_back(b);
		g[b].push_back(a);
	}

	k = 0;
	for (int i = 1; i <= n; i++) if (!v[i]) {
		d[k].clear();
		c[k] = dfs(i);
		k++;
	}
}

double solve (int u, int s) {
	if (d[u].count(s)) return d[u][s];

	int link = 0;
	for (int i = 0; i < k; i++) if (s&(1<<i)) {
		link += c[i];
	}
	if (link == n) return d[u][s] = 0;
	d[u][s] = (n-1)*1.0/(n-link);

	for (int i = 0; i < k; i++) if ((s&(1<<i)) == 0) {
		d[u][s] += solve (i, s | (1<<i)) * c[i]/(n-link);
	}
	return d[u][s];
}

int main () {
	int cas;
	scanf("%d", &cas);	
	for (int i = 1; i <= cas; i++) {
		init();
		printf("Case %d: %.6lf\n", i, solve (0, 1));
	}
	return 0;
}


你可能感兴趣的:(uva 11600 - Masud Rana(记忆化搜索))