lightoj 1287 Where to Run
阅读量:
searchstar
2019-11-07 16:14:32
Categories:
Tags:
大意:一个无向有权图,权值代表从一个点到另一个点所需时间。有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<vector<pii> > s;
void ClearEdges() { for (auto& i : s) i.resize(0); } void Init(int n) { ClearEdges(); s.resize(n+1); } void AddUndi(int u, int v, int w) { s[u].emplace_back(v, w); s[v].emplace_back(u, w); } } 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]; } vis[u][st] = true; if (st == (1 << n) - 1) { f[u][st] = 0; return res[u][st] = true; } f[u][st] = 5; int cnt = 0; for (auto& e : g.s[u]) { int nxt = st | (1 << e.first); if (st != nxt && dfs(nxt, e.first)) { ++cnt; f[u][st] += f[e.first][nxt] + e.second; } } if (cnt) { f[u][st] /= cnt; return res[u][st] = true; } else { f[u][st] = 0; return res[u][st] = false; } } int main() { int T;
scanf("%d", &T); for (int Ti = 1; Ti <= T; ++Ti) { int m;
scanf("%d%d", &n, &m); g.Init(n); while (m--) { int u, v, w; scanf("%d%d%d", &u, &v, &w); g.AddUndi(u, v, w); } for (int i = 0; i < n; ++i) { memset(vis[i], 0, (1 << n) * sizeof(bool)); } dfs(1, 0); printf("Case %d: %.10f\n", Ti, f[0][1]); }
return 0; }
|