D. Police Stations(超级原点+bfs)

题目

题意:

    给定一棵树,树上的节点有k个点是警察局。要求拆掉树上尽可能多的边,但要保证每个点离警察局的点的距离不超过d。
     2 n 3 1 0 5 , 1 k 3 1 0 5 , 0 d n 1 2 ≤ n ≤ 3·10^5, 1 ≤ k ≤ 3·10^5, 0 ≤ d ≤ n - 1

分析:

    有很多满足条件的点其实就应该想到超级原点,有了超级原点的想法后这题的思路就很自然了。建立一个超级原点连向警察局的那些点,那么就是建一棵树(因为要删去尽可能多的边),使得树上的点到原点的距离都小于等于k+1。那么以原点开始bfs,对于一个点要更新它原来相连的点时,如果那个点已经被更新了,那么说明那个点可以通过别的边到达原点,而不需要当前这条边,这种情况下就可以删去这条边了。

#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue> 
using namespace std;

map<int,map<int,int> >id;
vector<int> p,g[300005];
int vis[300005],flag[300005],pre[300005];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,k,d;
	cin >> n >> k >> d;
	for (int i = 1; i <= k; i++)
	{
		int x;
		cin >> x;
		if( flag[x] == 0 )
		{
			p.push_back(x);
			flag[x] = 1; 
		}
	}
	for (int i = 1; i < n; i++)
	{
		int x,y;
		cin >> x >> y;
		id[x][y] = id[y][x] = i;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	set<int> ans;
	queue<int> q;
	for (int i = 0; i < p.size(); i++)
	{
		q.push(p[i]);
		vis[p[i]] = 1;
	}
	while( !q.empty() )
	{
		int x = q.front();
		q.pop();
		for (int j = 0; j < g[x].size(); j++)
		{
			int t = g[x][j];
			if( vis[t] != 0 && pre[x] != t ) 
			{
				ans.insert(id[x][t]);
				continue;
			}
			if( vis[t] ) continue;
			pre[t] = x;
			vis[t] = 1;
			q.push(t);
		}
	}
	cout << ans.size() << '\n';
	set<int>:: iterator it;
	for (it = ans.begin(); it != ans.end(); it++)
	{
		cout << *it;
		if( it == --ans.end() ) cout << '\n';
		else cout << ' ';
	} 
	return 0;
}

发布了132 篇原创文章 · 获赞 6 · 访问量 7907

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/105150551