题目
题意:
有n个人,每一天都有两个人成为好朋友。现在需要安排旅行,对于每个人来说,如果他要去,那么他的朋友至少有k个都要去。输出每一天最多能安排的人。
分析:
首先关系我们就可以用图来表示,所以这题是一题图的题目。要使得一个子图的人都能去,则这个子图每个点的度都要大于等于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;
}