1. 程式人生 > >牛客小白月賽11 Rinne Loves Edges(dfs)

牛客小白月賽11 Rinne Loves Edges(dfs)

統計 ali 意義 can tail iostream int 當前 tex

Rinne Loves Edges

題目描述

Rinne 最近了解了如何快速維護可支持插入邊刪除邊的圖,並且高效的回答一下奇妙的詢問。 她現在拿到了一個 n 個節點 m 條邊的無向連通圖,每條邊有一個邊權 wiwi 現在她想玩一個遊戲:選取一個 “重要點” S,然後選擇性刪除一些邊,使得原圖中所有除 S 之外度為 1 的點都不能到達 S。 定義刪除一條邊的代價為這條邊的邊權,現在 Rinne 想知道完成這個遊戲的最小的代價,這樣她就能輕松到達 rk1 了!作為回報,她會讓你的排名上升一定的數量。

輸入描述:

第一行三個整數 N,M,S,意義如「題目描述」所述。

接下來 M 行,每行三個整數 u,v,w 代表點 u 到點 v 之間有一條長度為 w 的無向邊。

輸出描述:

一個整數表示答案。
示例1

輸入

4 3 1 
1 2 1 
1 3 1 
1 4 1

輸出

3

說明

需要使得點 2,3,4 不能到達點 1,顯然只能刪除所有的邊,答案為 3
示例2

輸入

4 3 1 
1 2 3 
2 3 1 
3 4 2

輸出

1

說明

需要使得點 4 不能到達點 1,顯然刪除邊 2?32?3是最優的。

備註:

2SN105,M=N?1,保證答案在 C++ long long 範圍內。
題解:
通過數據範圍 n = m-1 不難發現這是一棵樹,註意到樹上只有根和葉子的度可能為 1。
於是題目轉變求為了一棵根為 S 的樹,選擇性切掉一些邊,使得所有的葉子都不能到達根的最小代價。
讓我們考慮樹形dp(其實可能就是個統計算不上dp):設
fv 表示使得以 v 為根的子樹內的葉子到不了 v 的最小代價,轉移顯然枚舉每一條邊切不切就可以了。
方程大概是這樣:設當前我們要更新的點是 u,u 的一個兒子是 v,他們之間的邊的邊權是 w。則有轉移方程 fu+=min{fv,w}
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long
ll; 8 const int maxn = 1e5+10; 9 ll in[maxn]; 10 ll n,m,s,u,v,w; 11 struct node{ 12 ll to; 13 ll val; 14 }head,tail; 15 vector<node>g[maxn]; 16 ll dfs(ll pos,ll res,ll root){ 17 ll ans=0; 18 for(int i=0;i<g[pos].size();i++){ 19 head=g[pos][i]; 20 int to=head.to; 21 if(to==root) 22 continue; 23 else if(in[to]==1){ 24 ans+=head.val; 25 } 26 else{ 27 ans+=dfs(to,head.val,pos); 28 } 29 } 30 return min(ans,res); 31 } 32 int main() 33 { 34 cin>>n>>m>>s; 35 for(int i=0;i<m;i++){ 36 scanf("%lld %lld %lld",&u,&v,&w); 37 head.to=v; 38 head.val=w; 39 g[u].push_back(head); 40 head.to=u; 41 g[v].push_back(head); 42 in[u]++; 43 in[v]++; 44 } 45 ll ans=0; 46 for(int i=0;i<g[s].size();i++){ 47 node tmp=g[s][i]; 48 if(in[tmp.to]==1){ 49 ans+=tmp.val; 50 } 51 else{ 52 ans+=dfs(tmp.to,tmp.val,s); 53 } 54 } 55 printf("%lld\n",ans); 56 return 0; 57 }

 

牛客小白月賽11 Rinne Loves Edges(dfs)