/**//* 一棵树n<=1000(节点的分支<=8),Snail在根处,它要找到在某个叶子处的house 而其中一些节点上有worm,worm会告诉它的house是否在这个子树上 求Snail最快寻找到house走过路径的期望值 哈哈,自己花了2个多钟想出来的 论文《贪婪的动态规划》有
首先要弄清楚题目要算的是什么, 期望E = 某种策略下根到所有叶子的路径长度之和 / 叶子个数
显然,对于节点u,第一次试探的儿子v会影响后来的路径长度,这需要枚举 这样枚举第一个儿子v后,问题转化为u对剩下的子树的决策了 ----------OMG 需要用mask来记录了, mask <----- v + mask' (即枚举第一个v,剩下的是mask')
上面是定性的分析,那精确地定量分析是: dp[u,mask]表示如果house在u的子树内,现在考虑的子树是mask时的路径长度之和 转移就是枚举第一个子树v,分house可能在子树v和不在子树v内(这就是为什么dp[]是表示house在子树u内的) house在子树v时:dp[v] + leaf[v] leaf[v]为子树v的叶子数目,因为对于v内的每个叶子,都需要先从u走到v,即都要加1 house不在子树v时: dp[u,mask'] + 经过试探v增加的距离*mleaf[mask'] mleaf[mask']为mask'叶子数目 经过试探v增加的距离就要分v是否有worm了 如果v有worm,worm告诉Snail house不在v之内,显然增加的距离就是2了 如果v没有worm,就需要继续往v试探,增加的距离inc[v]也容易算出来.
这道题的启示就是要先弄明白要计算的是什么,知道了这个后才能正确地设计,避免走弯路 既然是期望,就讨论目标在所有位置的情况 ----------OMG 我的速度还是太慢了~~ */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<ctime> #include<bitset>
using namespace std;
const int INF = 1000000000; const int MAXN = 1010;
int dp[MAXN][1<<8], leaf[MAXN], inc[MAXN]; vector<int> e[MAXN]; bool mark[MAXN];
void dfs(int u) { leaf[u] = e[u].empty(); inc[u] = 0;//noted. for (vector<int> ::iterator it = e[u].begin(); it != e[u].end(); it++) { int v = *it; dfs(v); inc[u] += 2 + inc[v]; leaf[u] += leaf[v]; } if (mark[u]) { inc[u] = 0; } int n = e[u].size(); fill(dp[u], dp[u] + (1<<n), INF); dp[u][0] = 0; int mleaf[1<<8] = {0}; for (int mask = 1, limit = 1<<n; mask < limit ; mask++) { for (int j = 0; j < n; j++) { if (mask & (1<<j)) { int v = e[u][j], nn = e[v].size(); dp[u][mask] = min(dp[u][mask], dp[v][(1<<nn)-1] + leaf[v] + dp[u][mask^(1<<j)] + (inc[v]+2)*mleaf[mask^(1<<j)]); mleaf[mask] += leaf[v]; } } //cout<<mask<<" "<<dp[u][mask]<<endl; } //cout<<u<<" "<<leaf[u]<<" "<<dp[u][(1<<n)-1]<<endl; }
int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif
for (int n; scanf("%d", &n), n;) { fill(mark+1, mark+1+n, false); for (int i = 1; i <= n; i++) { e[i].clear(); } int root; char ch; for (int i = 1, x; i <= n; i++) { scanf("%d %c", &x, &ch); if (x == -1) { root = i; } else { e[x].push_back(i); } mark[i] = ch == 'Y'; } dfs(root); printf("%.4f\n", (double)dp[root][(1<<e[root].size())-1] / leaf[root]); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|