题目描述
Farmer John has NNN cows (2≤N≤105)(2≤N≤10^5)(2≤N≤105), conveniently labeled 1…N1…N1…N. There are MMM (1≤M≤2⋅105)(1≤M≤2⋅10^5)(1≤M≤2⋅105) pairs of friends among these cows.
A group of cows is called a “friendship group” if every cow in the group is reachable from every other cow in the group via a chain of friendships that lies solely within the group (friendships connecting to cows outside the group have no impact). The “strength” of a friendship group is the minimum number of friends of any cow in the group within the group times the number of cows in the group (again, note that friendships connecting to cows outside the group do not count for this definition).
Please find the maximum strength over all friendship groups.
翻译
无向图 GGG 中有 NNN 个点和 MMM 条边。选出其中的连通子图,使其最小度数与点数的乘积最大。
题解
给出结论,图中最小度数不超过 2m\sqrt{2m}2m。
感性理解:考虑极端情况完全图,上面结论是成立的。
这样我们就可以枚举最小度数 xxx,再找出最大的点数。
在原图中,先把度数小于 xxx 的点删掉,如果因此产生新的度数小于 xxx 的点,继续删。删完后,用 dfsdfsdfs 找最大连通块的大小即可。
时间复杂度为 O(nm)O(n\sqrt{m})O(nm)。
如果你 TLETLETLE 了,下面是一个优化方案:
从小到大枚举 xxx,设度数小于 xxx 删掉之后的图为 GxG_xGx,则对于 i<xi<xi<x,Gx⊂GiG_x\subset G_iGx⊂Gi。意思是每次删完的图都是之前的子图。
这样每次求 GxG_xGx 时就可以利用 Gx−1G_{x-1}Gx−1 来求。这样可以减小常数。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 1;
int n, m, maxn, minn, cnt;
int num[N], num1[N], fa[N], vis[N], bj[N];
ll ans = 0;
vector<int> v[N];
vector<int> pj[N];
bitset<N> Pj;
int dfs(int x) {
vis[x] = cnt;
int sum = 1;
for (auto i : v[x]) if (Pj[i] && vis[i] < cnt) sum += dfs(i);
return sum;
}
int f(int x) {
cnt++;
int maxn = 0;
for(auto i:pj[x]) Pj[i]=1;
for(auto i:pj[x]) if(vis[i]<cnt) maxn=max(maxn,dfs(i));
return maxn;
}
int read() {
int sum = 0, c = getchar();
while (c < 48 || c > 57) c = getchar();
while (c >= 48 && c <= 57) sum = sum * 10 + c - 48, c = getchar();
return sum;
}
void init()
{
int czn=sqrt(2*m);
for(int i=1;i<=n;i++) pj[1].push_back(i),num1[i]=num[i];
for(int i=2;i<=czn;i++){
queue<int> q;
for(auto j:pj[i-1]) if(num1[j]<i) bj[j]=1,q.push(j),num1[j]=0;
while(q.size()){
int k=q.front();
q.pop();
for(auto j:v[k]){
if(!bj[j]&&(--num1[j])<i) q.push(j),bj[j]=1,num1[j]=0;
}
}
for(auto j:pj[i-1]) if(!bj[j]) pj[i].push_back(j);
}
}
int main() {
n = read(), m = read();
for (int i = 1, u, V; i <= m; i++) {
u = read(), V = read();
v[u].push_back(V);
v[V].push_back(u);
num[u]++, num[V]++;
}
init();
int czn = sqrt(2 * m);
for (int i = czn; i >=1; i--) ans = max(ans, 1ll * i * f(i));
cout << ans<<endl;
}
该问题涉及图论,目标是找到一个无向图中的最大强度友谊群。最大强度定义为友谊群内每只奶牛的最小朋友数量乘以奶牛的数量。通过删除度数小于特定值的节点并使用深度优先搜索(DFS)找最大连通块,可以找到答案。时间复杂度为O(n√m),其中n是节点数,m是边数。给出的代码实现包括预处理步骤和优化策略,以减少计算量并避免超时。
1222

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



