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;
}
原文地址:https://www.cnblogs.com/LeafLove/p/13389019.html