复杂度:O(msqrt(m))
步骤:按点的度数分成两类,分别暴力
①统计每个点的度数
②入度<=sqrt(m)的分为第一类,入度>sqrt(m)的分为第二类
③对于第一类,暴力每个点,然后暴力这个点的任意两条边,再判断这两条边的另一个端点是否连接
因为m条边最多每条边遍历一次,然后暴力的点的入度<=sqrt(m),所以复杂度约为O(msqrt(m))
④对于第二类,直接暴力任意三个点,判断这三个点是否构成环,因为这一类点的个数不会超过sqrt(m)个,
所以复杂度约为O(sqrt(m)^3)=O(msqrt(m))
⑤判断两个点是否连接可以用set,map和Hash都行
const int MAXN = 100050;
set<int> mapp[MAXN];//用set是为了使用find
bool vis[MAXN];
int Du[MAXN];//统计各点的度
vector<int> high;
int N,M;//N是点数,M是边数。
int main(){
while(scanf("%d %d",&N,&M)!=EOF){
memset(Du,0,sizeof Du);
memset(vis,false,sizeof vis);
for(int i=1 ; i<=M ; ++i){
int a,b;
scanf("%d %d",&a,&b);
mapp[a].insert(b);
mapp[b].insert(a);
Du[a]++;Du[b]++;
}
int s = sqrt(M);
long long sum = 0;
for(int i=1 ; i<=N ; ++i){
if(Du[i]<=s){
vis[i] = true;
set<int>::iterator it;
for(it=mapp[i].begin() ; it!=mapp[i].end() ; ++it){
if(vis[*it])continue;
set<int>::iterator itt;
for(itt=it ; itt!=mapp[i].end() ; ++itt){
if(vis[*itt])continue;
if(mapp[*it].find(*itt) != mapp[*it].end()){
++sum;
}
}
}
}
else {
high.push_back(i);
}
}
for(int i=0 ; i<high.size() ; ++i){
for(int j=i+1 ; j<high.size() ; ++j){
if(mapp[high[i]].find(high[j]) == mapp[high[i]].end())continue;
for(int k=j+1 ; k<high.size() ; ++k){
if(mapp[high[i]].find(high[k])!=mapp[high[i]].end() && mapp[high[j]].find(high[k])!=mapp[high[j]].end())
++sum;
}
}
}
for(int i=1 ; i<=N ; ++i)mapp[i].clear();
high.clear();
}
return 0;
}