 /**//*
一棵樹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
搜索
最新評論

|
|