1. 程式人生 > 實用技巧 >Rinne Loves Edges

Rinne Loves Edges

Rinne Loves Edges

Problem:

Rinne 最近了解了如何快速維護可支援插入邊刪除邊的圖,並且高效的回答一下奇妙的詢問。

她現在拿到了一個 n 個節點 m 條邊的無向連通圖,每條邊有一個邊權 \(w_i\)

現在她想玩一個遊戲:選取一個 “重要點” S,然後選擇性刪除一些邊,使得原圖中所有除 S 之外度為 1 的點都不能到達 S。

定義刪除一條邊的代價為這條邊的邊權,現在 Rinne 想知道完成這個遊戲的最小的代價,這樣她就能輕鬆到達 rk1 了!作為回報,她會讓你的排名上升一定的數量。

Input:

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

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

Output:

一個整數表示答案。

Example:

Input

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

Output

3

Note

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

Input

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

Output

1

Note

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

Remark:

\(2 \leq S \leq N \leq 10^5\),M=N−1,保證答案在 C++ long long 範圍內。

題解:

有n個點m調邊並且m=n-1可知這個無向連通圖是一顆樹,因此求解刪除一些邊使度為1的點無法到達S的問題就轉化為了,使葉子節點無法到達S(轉化為了以S為根的樹)的刪除方案,用dfs搜尋每次維護刪除當前節點和父親節點之間的邊和所有子節點的刪除方案的最小值:

\[ans=min(dis[fa][now],\sum_{i=1}^{edges}ans_i) \]

Code:

/**********************************************************
* @Author: 			   Kirito
* @Date:   			   2020-07-28 07:47:01
* @Last Modified by:   Kirito
* @Last Modified time: 2020-07-28 08:23:58
* @Remark: 
**********************************************************/
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define Abs(x) (x>=0?x:(-x))
#define FAST ios::sync_with_stdio(false);cin.tie(0);
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

const int maxn=111111;
const ll upround=1e18;
vector<pll> tree[maxn];
int n,m,s,book[maxn];

ll dfs(ll fw,ll now)
{
	ll ans=0;
	for(auto &k:tree[now]){
		if(book[k.first]==0){
			book[k.first]=1;
			ans+=dfs(k.second,k.first);
			book[k.first]=0;
		}
	}
	if(ans==0)
		return fw;
	return min(fw,ans);
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	#endif
	FAST;
	cin>>n>>m>>s;
	for(int i=0;i<m;i++){
		int x,y,w;
		cin>>x>>y>>w;
		tree[x].push_back(make_pair(y,w));
		tree[y].push_back(make_pair(x,w));
	}
	book[s]=1;
	cout<<dfs(upround,s);
	return 0;
}