问题 A: 大红数星星
时间限制: 3 Sec 内存限制: 128 MB提交: 1066 解决: 67
[提交][状态][讨论版]
题目描述
“三角形十分的美丽,相信大家小学就学过三角形具有稳定性,三角形也是二维几何中最基本的必不可少的元素之……”,大红走在路上若有所思,突然抬头看到了天空中有很多很亮的星星划过,星星和他们划过的轨迹像极了一个无向图。于是好学的大红,就开始数起了“三角形”,1、2、3……数了好久,大红数的眼泪都掉下来了,所以他哭着请求你来帮他,你这么好心一定不会拒绝吧!大红的三角形的定义:如果存在这样的三个边(A,B)、(B,C)、(A,C)(无向边),则算一个三角形。
大红会告诉你这个图G=(V,E),点数(星星个数)n和边数(轨迹个数)m以及每条边的两个点。
两个三角形不同是:当对于两个三角形的边,某个三角形存在一条边在另一个三角形的边中无法找到!
输入
多组数据。
第一行一个整数T<=10表示数据组数。
对于每组数据的第一行n表示星星个数,m表示星星划过的轨迹的个数,
接下来m行表示每个星星划过的轨迹的端点x,y(1<=x,y<=n)。
1<=n<=100000,1<=m<=min(100000,n*(n-1)/2)
输出
对于每组数据输出一个整数,表示三角形的个数。
样例输入
1
3 3
1 2
2 3
1 3
样例输出
1
#include<iostream> #include<cstdio> #include<cstring> #include<sstream> #include<algorithm> #include<queue> #include<vector> #include<cmath> #include<map> #include<set> #include<fstream> #include<memory> #include<string> using namespace std; typedef long long LL; #define MAXN 100003 #define INF 1000000009 /* 寻找三角形的个数 思路: 1. 枚举所有边,然后枚举边上两个点中度比较小的 那个点中包含可以到达 枚举的边中另一点的边 +1 最后/3 2. 先把所有点按照度的大小排序,然后用数组记录一个点可以到达的顶点(要求顶点的度大于它) 然后枚举每条边,找两个顶点的公共元素数目 */ vector<int> E[MAXN]; vector<int> cnt[MAXN]; struct edge { int f, t; }; int T, n, m; vector<edge> a; int main() { edge tmp; int f, t; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { E[i].clear(); } a.clear(); int sum = 0; for (int i = 0; i < m; i++) { scanf("%d%d", &tmp.f, &tmp.t); E[tmp.f].push_back(tmp.t); E[tmp.t].push_back(tmp.f); a.push_back(tmp); } for (int i = 1; i <= n; i++) { sort(E[i].begin(), E[i].end()); } for (int i = 1; i <= n; i++) { for (int j = 0; j < E[i].size(); j++) { if (E[E[i][j]].size() > E[i].size()) cnt[i].push_back(E[i][j]);//可以到达的顶点 在这里保证顶点的度大于它的度 } } for (int i = 0; i < m; i++)//枚举所有边,找两个顶点的公共点个数 { f = a[i].f, t = a[i].t; int s1 = E[f].size(), s2 = E[t].size(); int z = 0, y = 0; while (z < s1&&y < s2) { if (E[f][z] < E[t][y]) { z++; } else if (E[f][z] > E[t][y]) { y++; } else { z++; y++; sum++; } } } printf("%d ", sum / 3); } }