赞
踩
无向图是一个稀疏图,点n<105
解法:暴力的方法可以使复杂度达到O(m×√m)
首先我们先是记录,使用邻接表记录无向图,记录每个点的出度,每条边用hash存下来,这个如何存呢,可以把边转换成一个独一无二的数,假设这条边端点是ab,可以存下a×n+b
储存过程结束后,开始从1-n枚举每个点设为x,然后找到所有和x相连的点记为y,并用link数组记录下link[y] = x,(此时相当于枚举了一条边)因为要找三元环,如果存在,另两个点肯定是和x相连的,这个时候分成两类
一:如果y点出度小于等于√m
二:如果y点出度大于√m
最终就完成了寻找,但是每个点都查找重复了三次,最后结果需要除以3。
复杂度分析:
为了方便说明我们按照上面叙述的算法,记枚举的第一个点为x,第二个点为y,最后一个点为z,
枚举的边用两端点表示如枚举的第一条边xy
下面进行分类讨论:
第一类点y的出度<=√m
第二类点y的出度>√m
综上所述复杂度是O(m√m
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
vector<int>G[maxn];
set<ll>st;
int vis[maxn],link[maxn],out[maxn];
int main(){
ll ans,sum;
int n,m,i,j,k,x,y,z,B;
while(scanf("%d%d",&n,&m) != EOF){
//初始化
B = sqrt(m);
st.clear();
for(i = 1; i <= n; i++){
G[i].clear();
vis[i] = out[i] = link[i] = 0;
}
for(i = 1; i <= m; i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
out[x]++;
G[y].push_back(x);
out[y]++;
st.insert((ll)x*n+y);//hash存边
st.insert((ll)y*n+x);
}
ans = 0;
for(i = 1; i <= n; i++){//枚举第一个点
x = i;
vis[x] = 1;//标记
for(j = 0; j < G[x].size(); j++)
link[G[x][j]] = x;
for(j = 0; j < G[x].size(); j++){
sum = 0;
y = G[x][j];//枚举第二个点,枚举了第一条边
if(vis[y])
continue;
if(out[y] <= B){//第一类
for(k = 0; k < G[y].size(); k++){
z = G[y][k];
if(link[z] == x)
sum++;
}
}
else{//第二类
for(k = 0; k < G[x].size(); k++){
z = G[x][k];
if(st.find((ll)z*n+y) != st.end())
sum++;
}
}
ans += sum;
}
}
printf("%lld\n",ans/3);
}
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。