大意:一个无向有权图,权值代表从一个点到另一个点所需时间。有n个点,标号0到n-1,初始点在0。定义一个点是好的,当且仅当这个点没去过,且从这个点能够沿着一条简单路径经过所有没去过的点。如果所在的点周围有cnt个好的点,那么有1/(cnt+1)的概率在当前点停留5min,各有1/(cnt+1)的概率前往周围那些点。当当前点周围没有好的点时终止。问期望的能坚持的时间是多久。
1 <= n <= 15
这么小的数据量当然是状压dp了。
定义f[i][st]为当前点是i,经过的点的集合为st。然后转移方程为
如何知道一个点是不是好的点呢?用dfs,假装去这个点了,然后递归判断从这个点是否能遍历所有的未经过点。
代码:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
#define MAXN 16
typedef pair<int, int> pii;
struct GRAPH {
<vector<pii> > s;
vector
void ClearEdges() {
for (auto& i : s)
.resize(0);
i}
void Init(int n) {
();
ClearEdges.resize(n+1);
s}
void AddUndi(int u, int v, int w) {
[u].emplace_back(v, w);
s[v].emplace_back(u, w);
s}
} g;
const double eps = 1e-12;
int n;
double f[MAXN][1 << MAXN];
bool vis[MAXN][1 << MAXN];
bool res[MAXN][1 << MAXN];
bool dfs(int st, int u) {
if (vis[u][st]) {
return res[u][st];
}
[u][st] = true;
visif (st == (1 << n) - 1) {
[u][st] = 0;
freturn res[u][st] = true;
}
[u][st] = 5;
fint cnt = 0;
for (auto& e : g.s[u]) {
int nxt = st | (1 << e.first);
if (st != nxt && dfs(nxt, e.first)) {
++cnt;
[u][st] += f[e.first][nxt] + e.second;
f}
}
if (cnt) {
[u][st] /= cnt;
freturn res[u][st] = true;
} else {
[u][st] = 0;
freturn res[u][st] = false;
}
}
int main() {
int T;
("%d", &T);
scanffor (int Ti = 1; Ti <= T; ++Ti) {
int m;
("%d%d", &n, &m);
scanf.Init(n);
gwhile (m--) {
int u, v, w;
("%d%d%d", &u, &v, &w);
scanf.AddUndi(u, v, w);
g}
for (int i = 0; i < n; ++i) {
(vis[i], 0, (1 << n) * sizeof(bool));
memset}
(1, 0);
dfs("Case %d: %.10f\n", Ti, f[0][1]);
printf}
return 0;
}