近期看的東西比較多也比較雜,遇到很多想做的題目,以此博客來記錄以免遺漏。
2019ICPC南京網絡賽D
給你一個DAG,保證只有1沒入邊,只有n沒出邊。每天做一個選擇:以等概率走向相鄰邊或者不動。第i天的花費是i。問你從1走到n的期望花費。
因爲是DAG,我們可以直接在上面做DP來求期望。要求花費,期望公式就是:
dp[u]表示u到n的期望花費
那麼問題就變成了如何求cost,其實也好求,再用一個DP求出期望天數就好了:
dp2[u]表示u到n的期望天數
dp2[u]就是上面對應的cost,道理也很簡單。
(寫這個好像只是爲了練一下LaTex?)
Code:
vector<int> G[maxn];
int out[maxn];
db dp1[maxn], dp2[maxn];
int n, m;
void init(){
rep(i, 1, n) dp1[i] = dp2[i] = 0, out[i] = 0, G[i].clear();
}
db dfs1(int u){
if(dp1[u]) return dp1[u];
if(!out[u]) return 0;
db sum = 0;
for(int v : G[u]){
sum += dfs1(v);
}
dp1[u] = sum / out[u] + 1 + 1.0 / out[u];
return dp1[u];
}
db dfs2(int u){
if(dp2[u]) return dp2[u];
if(!out[u]) return 0;
db sum = 0;
for(int v : G[u]){
sum += dfs2(v);
}
dp2[u] = sum / out[u] + dp1[u] * (1 + 1.0 / out[u]);
return dp2[u];
}
int main()
{
int T; scanf("%d", &T);
while(T--){
scanf("%d %d", &n, &m);
init();
rep(i, 1, m){
int u, v; scanf("%d %d", &u, &v);
out[u]++;
G[u].pb(v);
}
dfs1(1);
dfs2(1);
printf("%.2f\n", dp2[1]);
}
return 0;
}
也可以寫在一個dfs裏面,懶得改了。
IOI 2005 河流
中文就不說題意了。
很明顯的樹形DP,主要談談如果構造狀態。根據經驗,會先構造出dp[i][j],表示以i爲根的子樹中造了j個伐木廠的最小花費。
但是這樣子是轉移不出來的,因爲不知道一個節點的花費貢獻應該是多少,所以考慮再加入一維,表示該點的木頭運送到哪個點,這樣子花費就能算出來了.在寫之前算一算時間:照這樣子寫dfs裏面有4層循環,看上去複雜度有 接受不了,根據經驗樹形DP的複雜度往往不是表面的那樣。考慮狀態量和轉移量,其實也就是
的複雜度。
來寫寫轉移方程,轉移方程自然就是子樹合併啦
Codeforces 506D
Codeforces 193B
HDU 4405