稀疏图关于团的处理方法

团:指在一个无向图中的一个集合 \((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 类似。

posted @ 2024-12-16 18:23  ~Cyan~  阅读(1)  评论(0编辑  收藏  举报