决定小团体强度的值有两个:
- 团体内的最小度。
- 团体人数。
我们可以考虑枚举最小度求最大的团体人数。
我们发现小于原图最小度的度肯定不优,因为原图最小度可以直接选择包含全图使团体人数最大,这给了我们一个启发。
在之后,由于我们要增大团体内的最小度,所以最小度的点不会被包含,因此可以考虑删掉这些点。
这个时候问题由变回了原样,我们可以继续找最小度的点,如此类推。
注意到动态删点加维护连通块大小不好做,但是动态维护点的度数不难,我们先利用 set 维护删点顺序,再倒着加点,变成动态加点维护连通块大小,并查集即可维护。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=3e5+5;
LL n,m,x,y,ans,fa[N],a[N],du[N],d[N],sz[N],vis[N];
vector<LL>v[N];
stack<LL>s;
set<pair<LL,LL>>p;
LL find(LL x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)fa[i]=i,a[i]=i,sz[i]=1;
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
du[x]++,du[y]++;
}
for(int i=1;i<=n;i++)
{
p.insert({du[i],i});
}
while(!p.empty())
{
LL t=(*p.begin()).second;
p.erase(p.begin());
s.push(t);
d[t]=du[t];
for(LL i:v[t])
{
if(d[i])continue;
p.erase(p.lower_bound({du[i],i}));
du[i]--;
p.insert({du[i],i});
}
}
for(int i=1;i<=n;i++)
{
LL t=s.top();
vis[t]=1;
s.pop();
for(LL j:v[t])
{
if(vis[j]==0)continue;
LL fx=find(t),fy=find(j);
if(fx!=fy)
{
fa[fx]=fy;
sz[fy]+=sz[fx];
}
}
ans=max(ans,sz[find(t)]*d[t]);
}
printf("%lld",ans);
return 0;
}
该文讨论了一个关于图的问题,寻找具有最大团体人数同时保证团体内最小度的算法。通过枚举最小度并动态删除节点,使用并查集维护连通块大小,最终找到最大团体的解。
543

被折叠的 条评论
为什么被折叠?



