emmm,蒟蒻發現自己的dp太辣雞了。。。所以來練練dp,這題的話實際上應該算是樹dp的入門題吧,轉移還是挺好想的。
每次在每個節點都會有個選擇,就是選還是不選,如果選的話,那麼它的兒子節點就不能選,如果不選的話它的兒子節點就可以選,也就是說我們需要另開一維狀態來記錄每個節點是否選自己的情況,那麼就很容易得出如下方程:
dp[x][0]+=max(0,max(dp[v][1],dp[v][0]));//如果不選當前節點,那麼兒子節點可以任意選
dp[x][1]+=max(0,dp[v][0]);//如果選擇當前節點,那麼只能選擇兒子節點不存在的情況
ac**
#include using namespace std;
vectorson[10010];
void dfs(int x)
}int main()
int root;
for (int i = 1; i <= n; ++i)
if (!v[i])
dfs(root);
cout << max(f[root][0], f[root][1]) << endl;
}
演算法競賽高階指南原文:思路:正如深度優先和廣度優先都可以對樹或圖進行遍歷一樣,除了自頂向下的遞迴外。我們也可以使用自底向上的topo排序來執行樹形dp。但通常前者就足夠了。
每堂課和學它必修的課連一條邊。為了方便,每個入度為0的課(即可以直接選的課)與乙個虛擬的n+1節點連一條邊,然後在樹上跑01揹包即可。
#include #include #include #include #include using namespace std;
vectorson[310];
int f[310][310], s[310], n, m;
void dp(int x)
if (x != 0) // x不為0時,選修x本身需要占用1門課,並獲得相應學分
for (int t = m; t > 0; t--)
f[x][t] = f[x][t - 1] + s[x];
}int main()
memset(f, 0xcf, sizeof(f)); // -inf
dp(0);
cout << f[0][m] << endl;
}
乙個樹形水系,有 \(n\) 個結點,根結點稱為源點,葉子結點稱為匯點,每條邊都有水量限制$c(x,y) \((\)x,y$ 為這條邊的兩個端點),源點單位時間流出的水量稱為整個水系的流量,求以哪乙個結點作為源點整個水系的流量最大。首先得理解到這是一道「不定根」的樹形dp問題,這類題目的特點是,給定乙個樹形結構,需要以每個結點為根進行一系列統計。我們一般通過兩次掃瞄來求解此類問題:(也即:二次掃瞄與換根法)
首先,我們任選乙個結點root
,然後樹形dp一下,求出 \(d_\) 陣列( \(d[i]\) 表示在以 \(i\) 為根的子樹中流量的最大值)。然後設 \(f_x\) 表示以 \(x\) 為源點,流向整個水系的最大流量,則顯然 \(f_ = d_\) 假設 \(f_x\) 已經求出,考慮其子結點 \(y\) ,則 \(f[y]\) 包含兩部分:
從 \(y\) 流向以 \(y\) 為根的子樹的流量,已經計算出來。
從 \(y\) 沿著到父節點 \(x\) 的河道,進而流向水系中其他部分的流量。
由題意可知,從 \(x\) 流向 \(y\) 的流量為 \(min(d_y,c_)\) ,所以從 \(x\) 流向除 \(y\) 以外其他部分的流量分量是其兩者之差:\(f_x - min(d_y,c_)\) 於是,把 \(y\) 作為源點,先從流到 \(x\),再流向其他部分的流量就是吧這個「差值」再與 \(c_\) 取較小值後的結果
\[if(deg[x] > 1) \to f[y] = d[y] + min(f[x] - min(d[y],c[x][y]) - c[x][y])\\
if(deg[x] == 1) \to f[y] = d[y] + c[x][y]
\]這是乙個由下而上的遞推方程,所以我們可以通過一次dfs來完成
ac **
// murabito-b 21/04/26
#include using namespace std;
#define fi first
#define se second
const int n = 2e5 + 5;
using pii = pair;
vectorg[n];
int dp[n], d[n], f[n];
void dfs(int u, int fa)
}void dfs1(int u, int fa) else
dfs1(v, u);
}}void solve()
for (int i = 1; i < n; ++i) );
g[v].push_back();
d[u]++, d[v]++;
}dfs(1, -1);
// f[1] = dp[1];
dfs1(1, -1);
int ans = 0;
for (int i = 1; i <= n; ++i) ans = max(ans, f[i]);
cout << ans << '\n';
}int main()
動態規劃 樹形DP
樹形dp,即在樹上進行的動態規劃,由於樹固有的遞迴性質,因此樹形dp往往也遞迴進行。某大學有 n nn 個職員,編號為 1.n1.n 1.n 他們之間有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。現在有個周年慶宴會,宴會每邀請來乙個職員都會增加一定的快樂指數 r ...
( 動態規劃專題 ) 樹形dp
動態規劃專題 樹形dp 直接看例題 p2015 二叉蘋果樹 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3...
動態規劃(7) 樹形DP
昨天本來就能寫的,結果寫了倆個題寫了四五個小時,於是乎拖到今天了。這個題就很好寫了,不像狀態壓縮,真的是難理解 大佬部落格 f u 0 表示從以u為根節點,不選u的方案。f u 1 表示從以u為根節點,選u的方案。所以f u 0 max f si 0 f si 1 i是遍歷下一層的子節點 f u 0...