题目大意:给出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(记忆化搜索),布布扣,bubuko.com
原文:http://blog.csdn.net/keshuai19940722/article/details/20795479