• hud 6184


    $n$ 点 $m$ 边的图求多少对三元环公用一条边
    变无向图为有向图

    建图方法:
    对于每条无向边 度数小的端点向度数大的端点连边
    度数相同则编号小的点向编号大的点连边
    这样就构成 $DAG$
    遍历:
    遍历每条边的 $u$
    标记另一端点 $v$
    遍历该边的 $v$
    如果 $v$ 的 $v_2$ 的标记与 $v$ 相同
    则说明构成了三元环 $(u, v), (v, v_2), (u, v_2)$

    记录每条边构成的三元环的个数 $x$
    组合数 $x choose 2$ 加入答案

    由于连边时每个点的出边都要 $<= sqrt(m)$ 

    所以时间复杂度 $O(m sqrt(m))$

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <map>
    #include <cstdlib>
    
    using namespace std;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    #undef gc
    
    const int N = 1e6 + 10, M = 2e5 + 10;
    
    int du[N], a[M], b[M];
    int n, m, head[N], cnt, Ans[N];
    struct Node {int v, nxt, id;} G[M];
    struct Node2 {int first, second;} vis[N];
    
    inline void Add(int u, int v, int id) {
        G[++ cnt].v = v; G[cnt].nxt = head[u]; G[cnt].id = id; head[u] = cnt;
    }
    
    void Clear() {
        cnt = 0;
        memset(vis, 0, sizeof vis);
        memset(du, 0, sizeof du);
        memset(Ans, 0, sizeof Ans);
        for(int i = 1; i <= n; i ++) head[i] = -1;
    }
    
    int main() {
        while(scanf("%d %d", &n, &m) == 2) {
            Clear();
            for(int i = 1; i <= m; i ++) {
                a[i] = read(), b[i] = read();
                du[a[i]] ++, du[b[i]] ++;
            }
            for(int i = 1; i <= m; i ++) {
                if(du[a[i]] > du[b[i]] || (du[a[i]] == du[b[i]] && a[i] > b[i])) swap(a[i], b[i]);
                Add(a[i], b[i], i);
            }
            int use_num = 0;
            for(int i = 1; i <= m; i ++) {
                use_num ++;
                for(int j = head[a[i]]; ~ j; j = G[j].nxt) {
                    vis[G[j].v] = (Node2) {use_num, G[j].id};
                }
                for(int j = head[b[i]]; ~ j; j = G[j].nxt) {
                    if(vis[G[j].v].first == use_num) {
                        Ans[i] ++, Ans[G[j].id] ++, Ans[vis[G[j].v].second] ++;
                    }
                }
            }
            long long answer = 0;
            for(int i = 1; i <= m; i ++) if(Ans[i] > 1) answer += (Ans[i] * (Ans[i] - 1) / 2);
            printf("%lld
    ", answer);
        }
        return 0;
    }
  • 相关阅读:
    C++泛型函数及模版类
    android逆向入门及工具下载
    排序算法之交换排序
    索尼法则=?职场法则
    2014年5月20日---一个值得纪念的日子
    C#的委托是什么?
    物联网RFID安全研究
    [转]nmap使用方法
    [转]中间人攻击-ARP毒化
    15019:Only the instance admin may alter the PermSize attribute
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9528637.html
Copyright © 2020-2023  润新知