• [hdu 6184 Counting Stars(三元环计数)


    hdu 6184 Counting Stars(三元环计数)

    题意:

    给一张n个点m条边的无向图,问有多少个(A-structure)
    其中(A-structure)满足(V=(A,B,C,D)) && (E=(AB,BC,CD,DA,AC))

    显然(A-structure)是由两个有公共边的三元环构成的
    (1 <=n <= 1e5)
    (1 <= m <= min(2e5,n*(n-1)/2))

    思路:

    三元环计数
    做法1、
    ①统计每个点的度数
    ②入度(<=sqrt(m))的分为第一类,入度(>sqrt(m))的分为第二类
    ③对于第一类,暴力每个点,然后暴力这个点的任意两条边,再判断这两条边的另一个端点是否连接
    因为(m)条边最多每条边遍历一次,然后暴力的点的入度(<=sqrt(m)),所以复杂度约为(O(msqrt(m)))
    ④对于第二类,直接暴力任意三个点,判断这三个点是否构成环,因为这一类点的个数不会超过(sqrt(m))个,所以复杂度约为(O(sqrt(m)^3)=O(msqrt(m)))
    ⑤判断两个点是否连接可以用set,map和Hash都行,根据具体情况而行
    这种做法建的是双向边,常数很大

    更优的做法2、建有向边 复杂度为(O(msqrt(m)))
    对所有边按照两端点的度数定向,度数小的往度数大的走,度数相同则按编号小到大走,这样定向后
    可以保证是个有向无环图。
    为什么呢,要想定向存在环,则这个环上的点度数必须相同,由于保证了编号从小到大走
    所以是不可能存在环的。
    这样定向同时还保证了每个点的出度不超过(sqrt(m)),很容易证明,如果存在一个点出度超过了(sqrt(m)),则说明存在其他(sqrt(m))个点的度数(>sqrt(m)),算起来超过边数(m)了。

    对于这道题,我们在求三元环的时候,统计一下每条边有多少对点能构成三元环,(C(cnt,2))累计一下即可

    做法1、

    #include<bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    void read(int &x){
        x = 0;
        char c = getchar();
        while(c < '0' || c > '9')  c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
    }
    const int N = 1e5 + 10;
    set<LL> g;
    int deg[N];
    vector<int> G[N];
    int vis[N],vi[N];
    int main(){
    
        int  n, m, u, v, Sz;
        while(scanf("%d%d",&n,&m) != EOF){
            Sz = sqrt(m + 0.5);
            g.clear();
            for(int i = 1;i <= n;i++){
                vis[i] = vi[i] = deg[i] = 0;
                G[i].clear();
            }
            for(int i = 0;i < m;i++){
                scanf("%d%d",&u,&v);
                g.insert(u + 1LL * v * n);
                g.insert(v + 1LL * u * n);
                deg[u]++,deg[v]++;
                G[u].push_back(v);
                G[v].push_back(u);
            }
            LL ans = 0;
            for(int u = 1;u <= n;u++){
                vis[u] = 1;
                for(auto v:G[u]) vi[v] = u;
                for(auto v:G[u]){
                    int cnt = 0;
                    if(vis[v]) continue;
                    if(deg[v] <= Sz){
                        for(auto vv:G[v]){
                            if(vi[vv] == u) cnt++;
                        }
                    }else{
                        for(auto vv:G[u]){
                            if(g.find(1LL * v * n + vv) != g.end()) cnt++;
                        }
                    }
                    ans += 1LL * cnt * (cnt - 1) / 2;
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    

    做法二、

    #include<bits/stdc++.h>
    #define LL long long
    #define P pair<int,int>
    using namespace std;
    void read(int &x){
        x = 0;
        char c = getchar();
        while(c < '0' || c > '9')  c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
    }
    const int N = 1e5 + 10;
    set<LL> g;
    int deg[N];
    vector<pair<int,int> > G[N];
    int vi[N];
    int X[N * 2],Y[N * 2],cnt[N],pos[N];
    int main(){
        int  n, m, u, v, Sz;
        while(scanf("%d%d",&n,&m) != EOF){
            Sz = sqrt(m);
            for(int i = 1;i <= n;i++){
                vi[i] = deg[i] = pos[i] = 0;
                G[i].clear();
            }
            g.clear();
            int tot = 0;
            for(int i = 0;i < m;i++){
                scanf("%d%d",&X[i],&Y[i]);
                u = X[i],v = Y[i];
                deg[u]++,deg[v]++;
            }
            for(int i = 0;i < m;i++){
                cnt[i] = 0;
                if(deg[X[i]] < deg[Y[i]]) G[X[i]].push_back(make_pair(Y[i],i));
                else if(deg[Y[i]] < deg[X[i]]) G[Y[i]].push_back(P(X[i],i));
                else{
                    if(X[i] < Y[i]) G[X[i]].push_back(P(Y[i],i));
                    else G[Y[i]].push_back(P(X[i],i));
                }
            }
            LL ans = 0;
            for(int i = 0;i < m;i++){
                u = X[i],v = Y[i];
                for(auto vp:G[u]) pos[vp.first] = vp.second,vi[vp.first] = i + 1;
                for(auto vp:G[v]){
                    int vv = vp.first;
                    if(vi[vv] == i + 1){
                        cnt[i]++;
                        cnt[pos[vv]]++;
                        cnt[vp.second]++;
                    }
                }
            }
            for(int i = 0;i < m;i++) ans += 1LL * cnt[i] * (cnt[i] - 1) / 2;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    使用Property+使用构造+构建自定义类+使用List<自定义类>(项目)
    几乎全面的食品英文总结
    网络资源深入剖析Binding(学习)
    WPF入门知识(学习)
    Get children gameobjects array and assign the script inside
    Unity3D + C#: Cloning the Content of a Serializable Class
    Use Web Fonts and the @fontface CSS Method
    Good XAML Patterns
    Coroutines & Yield
    How to make a mini map for your scene in Unity3d
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7474761.html
Copyright © 2020-2023  润新知