稀疏图关于团的处理方法
团:指在一个无向图中的一个集合 \((V,E)\),满足点集中的点两两之间都有边相连。
问题 1:\(n\) 个点的无向图,有 \(m\) 条边,无重边与自环,求稀疏图的不同的团的个数。
\(n \le 1000 , m \le 1000\)
考虑使用三元环计数的方法,把无向边按度数大小定向,使得每个点的出度都在 \(O(\sqrt{2m})\)。证明
然后直接暴力做,就是 \(O(poly(m)2^{\sqrt{2m}})\)。
然后考虑 meet in middle,用高维前缀和维护,复杂度就变成了 \(O(poly(m)2^{\frac{\sqrt{2m}}{2}})\)。
点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define lowbit(x) x&(-x)
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir;
inline int read(){
int x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
while(isdigit(c)){x=x*10+(c^48); c=getchar();}
return x*f;
}
const int inf=1e18,N=1e3+5,M=5e6+5,mod=1e9+7;
int n,m,s;
int du[N],vis[N];
int _u[N],_v[N];
int op[N],mpl[N],mpr[N];
bool C[M];
int sum[M],ans;
vector<int> ed[N],re[N];
inline bool cmp(int x,int y){
if(du[x]!=du[y]) return du[x]<du[y];
return x<y;
}
inline void solve(){
int mid=s/2;
for(int i=1;i<=s;i++) vis[op[i]]=i,mpl[i]=mpr[i]=0;
for(int i=1;i<=s;i++){
int x=op[i];
for(auto v:re[x]){
if(vis[v]){
int id=vis[v];
if(id<=mid) mpl[i]|=(1<<(id-1));
else mpr[i]|=(1<<(id-mid-1));
if(i<=mid) mpl[id]|=(1<<(i-1));
else mpr[id]|=(1<<(i-mid-1));
}
}
}
int st=(1<<mid);
C[0]=1;
for(int i=1;i<st;i++){
int num=lowbit(i),x=__lg(num)+1;
C[i]=C[i^num]&((mpl[x]&i)==(i^num));
if(C[i]) sum[i]=1;
else sum[i]=0;
}
int Y=st-1;
for(int j=1;j<=mid;j++) for(int i=1;i<st;i++) if(i>>(j-1)&1) sum[i]+=sum[i^(1<<(j-1))];
(ans+=sum[st-1])%=mod;
st=(1<<(s-mid));
C[0]=1;
for(int i=1;i<st;i++){
int num=lowbit(i),x=__lg(num)+1+mid;
C[i]=C[i^num]&((mpr[x]&i)==(i^num));
if(C[i]){
int c=__builtin_popcount(i);
int now=Y;
for(int j=0;j<s-mid;j++) if(i>>j&1) now&=mpl[j+mid+1];
ans=(ans+sum[now]+1)%mod;
}
}
for(int i=1;i<=s;i++) vis[op[i]]=0;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
ed[u].push_back(v);
ed[v].push_back(u);
_u[i]=u,_v[i]=v;
du[u]++,du[v]++;
}
for(int i=1;i<=m;i++){
int u=_u[i],v=_v[i];
if(du[u]>du[v]||((du[u]==du[v])&&u>v)) swap(u,v);
re[u].push_back(v);
}
for(int x=1;x<=n;x++){
s=0;
for(auto v:re[x]) op[++s]=v;
solve();
}
cout<<(ans+n)%mod<<'\n';
}
问题 2:求最大团
与问题 1 类似。