p2014 [ctsc1997]選課
p2014 [ctsc1997]選課
solution
樹上揹包模板題
因為有多節課是沒有先修課的,所以並不是只有一棵樹,用乙個0號點作為沒有先修課的課程的先修課,這樣就合併成了一棵樹,只要選取m+1個點(必選0)即可。
轉移方程: dp[u][j] = max(dp[u][j - k] + dp[v][k],dp[u][j]);
01揹包,所以j要倒序列舉
**
#include
using
namespace std;
const
int sz =
320;
typedef
long
long ll;
int n,m,fist[sz]
,temp;
int dp[sz]
[sz]
,b[sz]
,a;//dp[i][j] 為在i為根的子樹上選擇j個節點的最大學分
struct zt
line[sz]
;inline
void
add(
int a,
int b)
; fist[a]
= temp;
}inline
intdfs
(int u)
}int
main()
dfs(0)
;printf
("%d\n"
,dp[0]
[m])
;return0;
}
p1273 有線電視網
p1273 有線電視網
solution
與上題類似,改為只選葉子節點,同時減去邊的花費。
令dp[i][j]為以i為根的子樹中選擇j個葉子節點的最大收益。
轉移方程:dp[u][j] = max(dp[u][j],dp[u][j - k] + dp[v][k] - line[i].w)
最終結果可能是負值,所以dp陣列初始化為乙個極小值。
**
#include
using
namespace std;
const
int sz =
3000+20
;const
int inf =
0x3f3f3f3f
;typedef
long
long ll;
int n,m,fist[sz]
,val[sz]
,temp,dp[sz]
[sz]
;struct zt
line[sz]
;inline
void
add(
int x,
int y,
int z)
; fist[x]
= temp;
}inline
intdfs
(int u)
int sum =0;
// 當前節點為根時,子樹中葉子節點的數量
for(
int i = fist[u]
;i !=-1
;i = line[i]
.nxt)
return sum;
}int
main()
}for
(int i = n - m +
1;i <= n;i ++
)scanf
("%d"
,&val[i]);
for(
int i =
1;i <= n;i ++
) dp[i][0
]=0;
dfs(1)
;for
(int i = m;i >=
0;i --)}
return0;
}
2020.7.12 重建道路 樹上揹包
初始化 void init struct edges edge maxm 1 無向圖則需要乘2 inline void add int u,int v head u cnt int dp m m siz m tmp m int n,m void dfs int u,int fa siz u siz ...
樹上依賴揹包總結
做了很多關於樹上dp的題有些使用了nm 2的演算法來進行dp,可是當m過大時方法不大試用,又可以對這種演算法進行優化,如dfs序或者直接樹上合併揹包。當輸出方案時又需要多叉轉二叉進行dp尋找方案,很多方法於是乎總結一下。w i 表示第i個節點的重量,v i 表示第i個節點的價值,f i j 表示以i...
動態規劃 樹上揹包
題意 每個頂點有兩個權值b和w。最多3000個節點的樹,分成恰好m個非空的連通塊,使得盡可能多的連通塊滿足w的和嚴格大於b的和。樹上揹包的套路題,這裡揹包 dp i j 表示以i為根的子樹,已經劃分了 j 個連通塊,包括根節點在內的最後乙個連通塊沒有劃分,能取到的最優值。這一題最優值看起來有兩維,但...