• HDU6184【Counting Stars】(三元环计数)


    题面

    传送门

    给出一张无向图,求 (4) 个点构成两个有公共边的三元环的方案数。

    题解

    orz余奶奶,orz zzk

    首先,如果我们知道经过每条边的三元环个数(cnt_i),那么答案就是(sum_{i=1}^m{cnt_ichoose 2})

    所以现在问题就是该怎么数三元环

    据说有一个设阈值的(O(msqrt{m}))的做法,不过常数太大了,这里不讲

    我们把每一条边重定向,设它连接的两个点的度数分别为(deg_u)(deg_v),那么把这条边定为从度数大的连向度数小的,如果度数相同按标号大小。这样显然可以建出一个有向无环图

    所以怎么找环呢

    我们枚举点(u),并枚举它的所有出边,把出边指向的点(v)标记上(u)。然后再枚举一边出边,并对每个(v)也枚举出边,如果(v)的出边指向的点(w)上的标记是(u)那么说明找到了一个三元环

    显然,每个三元环都会被统计恰好一次

    接下来的问题是复杂度,我们要证明它的上界是(O(msqrt{m}))

    1.(forall v,out_vleq sqrt{m}),每一次枚举(v)的出边的复杂度不会超过(O(sqrt{m})),所以这一部分复杂度不会超过(O(msqrt{m}))

    2.(forall v,out_vgeq sqrt{m}),因为在这种情况下必有(deg_ugeq deg_v),所以所有这样的(u)不会超过(O(sqrt{m}))个,每一个(out_v)的贡献最多是(sqrt{m}out_v),由于(sum out_v=O(m)),所以这一部分的复杂度也不会超过(O(msqrt{m}))

    不过这个做法常数不知道比设阈值小到哪里去了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define ll long long
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')if(ch==EOF)return -1;
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=2e5+5;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    struct EG{int u,v;}E[N];
    int n,m,tim,deg[N],pt[N],vis[N],cnt[N];ll res;
    int main(){
    //    freopen("testdata.in","r",stdin);
        while(~(n=read(),m=read())){
            tot=tim=0;fp(i,1,n)head[i]=deg[i]=vis[i]=0;
            fp(i,1,m)E[i].u=read(),E[i].v=read(),++deg[E[i].u],++deg[E[i].v],cnt[i]=0;
            fp(i,1,m)deg[E[i].u]>deg[E[i].v]||(deg[E[i].u]==deg[E[i].v]&&E[i].u>E[i].v)?add(E[i].u,E[i].v):add(E[i].v,E[i].u);
    		fp(u,1,n){
    			++tim;go(u)pt[v]=i,vis[v]=tim;
    			for(R int k=head[u];k;k=e[k].nx)go(e[k].v)
    				if(vis[v]==tim)++cnt[i],++cnt[k],++cnt[pt[v]];
    		}
            res=0;
            fp(i,1,m)res+=1ll*cnt[i]*(cnt[i]-1)>>1;
            printf("%lld
    ",res);
        }
        return 0;
    }
    
  • 相关阅读:
    JS精度问题(0.1+0.2 = 0.3吗?)
    力导向算法的研究与改进
    React Hooks的memo和useCallback
    React Hooks vs Vue Composition Api
    docker常用命令
    win10一台电脑上配置多个git账户
    eslint+prettier 统一代码风格
    c#中关于值类型,引用类型在栈,堆栈的分配
    js里的__proto__和prototype
    golang之冒泡排序
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10582360.html
Copyright © 2020-2023  润新知