E. Trips(set删边+分析)

题目

题意:

    有n个人,每一天都有两个人成为好朋友。现在需要安排旅行,对于每个人来说,如果他要去,那么他的朋友至少有k个都要去。输出每一天最多能安排的人。
     2 n 2 1 0 5 , 1 m 2 1 0 5 , 1 k < n 2≤n≤2⋅10^5,1≤m≤2⋅10^5 , 1≤k<n

分析:

    首先关系我们就可以用图来表示,所以这题是一题图的题目。要使得一个子图的人都能去,则这个子图每个点的度都要大于等于k。如果说一个人最后都没有k个朋友,那么我们自然就可以不用考虑他,那么我们就可以把它删去。这样的话我们就考虑到着遍历,这样我们就可以删边,从而进行删点,来维护一张满足条件的子图。
    对于具有删边的操作,所以图自然使用set来维护。对于一个不满足条件的点,我们只要把它删去即可。由于删去这个点可能会导致一系列的连锁反应,所以我们需要用搜索来维护这个删点的过程。对于深搜来说,可能在删这条边时由于连锁反应删去了后面要遍历的边,从而导致遍历出现问题,所以就用广搜来做,一个点删干净后再考虑别的要删去的点。

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

set<int> g[200005]; 
int x[200005],y[200005],vis[200005],ans;
vector<int> res;
queue<int> q;

void todo(int k)
{
	while( !q.empty() )
	{
		int x = q.front();
		q.pop();
		set<int>::iterator it;
		for (it = g[x].begin(); it != g[x].end(); it++)
		{
			if( vis[*it] ) continue;
			g[*it].erase(x);
			if( g[*it].size() < k )
			{
				vis[*it] = 1;
				ans --;
				q.push(*it);
			}
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m,k;
	cin >> n >> m >> k;
	ans = n; 
	for (int i = 1; i <= m; i++)
	{
		cin >> x[i] >> y[i];
		g[x[i]].insert(y[i]);
		g[y[i]].insert(x[i]);
	}
	for (int i = 1; i <= n; i++)
	{
		if( g[i].size() < k )
		{
			q.push(i);
			vis[i] = 1;
			ans --;
		}
	}
	todo(k);
	res.push_back(ans);
	for (int i = m; i > 1; i--)
	{
		if( vis[x[i]] == 0 && vis[y[i]] == 0 )
		{
			g[x[i]].erase(y[i]);
			g[y[i]].erase(x[i]);
			if( g[x[i]].size() < k )
			{
				vis[x[i]] = 1;
				q.push(x[i]);
				ans --;
			}
			if( g[y[i]].size() < k )
			{
				vis[y[i]] = 1;
				q.push(y[i]);
				ans --;
			}
			todo(k);
		}
		res.push_back(ans);
	}
	for (int i = res.size() - 1; i >= 0; i--)
	{
		cout << res[i] << '\n';
	}
	return 0;
}

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

猜你喜欢

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