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\n", answer);
    }
    return 0;
}

 

posted @ 2018-08-24 11:08  xayata  阅读(135)  评论(0编辑  收藏  举报