http://acm.hdu.edu.cn/showproblem.php?pid=6184
先遍历所有的点,对于每个点再遍历所有的边,对于每一条边计算以这条边为三元环的某一条边的三元环个数,当然已经遍历过的点就不要再出现了
对于一条边,我们枚举时可以从这两个点任意取一个点去枚举第三个点,所以我们可以通过比较两个点谁的出边多来决定枚举谁,但实际就代码写法而言,是通过比较其出边与m的开平方的大小来决定的。
#include <iostream>
#include <cstring>
#include<cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include<set>
#pragma warning(disable:4996)
using namespace std;
typedef long long LL;
vector<int> G[100000 + 10];
bool vis[100000 + 10];
int link[100000 + 10], out[100000 + 10];
set<LL> S;
int main()
{
int n, m;
while (scanf("%d%d", &n, &m) == 2)
{
int u, v, B;
LL ans , sum;
S.clear();
for (int i = 1; i <= n; i++) {
G[i].clear();
vis[i] = link[i] = out[i] = 0;
}
for (int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
S.insert(LL(u*n + v));
S.insert(LL(v*n + u));
out[u]++;
out[v]++;
}
B = sqrt(m + 0.5);
ans = 0;
for (int i = 1; i <= n; i++)
{
vis[i] = true;
for (int j = 0; j < G[i].size(); j++)
link[G[i][j]] = i;
for (int j = 0; j < G[i].size(); j++)
{
sum = 0;
int t = G[i][j];
if (vis[t]) continue;
if (out[t] <= B) {
for (int k = 0; k < G[t].size(); k++)
if (link[G[t][k]] == i) sum++;
}
else {
for (int k = 0; k < G[i].size(); k++)
if (S.find(LL(G[i][k] * n + t)) != S.end()) sum++;
}
ans += sum * (sum - 1) / 2;
}
}
printf("%lld\n", ans);
}
//system("pause");
}