定义 “星星” 是这样的一张图,它有四个点、五条边。五条边中有四条构成一个环,第五条边是环中的一个弦。
现在有一张 N 个点、M 条边的无向简单图,你需要计算图中有多少个不同的“星星”子图。
这里我们定义两张子图不同,当且仅当它们的边集不完全相同。
Hint:一个四阶完全图恰好有 6 个不同的“星星”子图。
翻译来自51nod
一个“星星”子图肯定是由两个有一条邻边的三元环拼起来的。我们统计每条边经过多少个三元环然后算一下就可以了
统计无向图中的三元环常常这样做:我们首先算出所有点的度数,并按照度数给边定向。
我们钦定从只从度数较小的点走向度数较大的点,度数相同就从编号小的走向编号大的。然后我们枚举一条边,并分别枚举这条边的两个端点连出去的所有边看香蕉了多少次就行了
这样做是 n m n\sqrt m nm 的
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int N=600005;
int ls[N],d[N],edCnt;
int lxf[N],wjp[N];
LL cnt[N];
std:: vector <pair> G[N],vec;
void add_edge(int x,int y,int id) {
G[x].push_back(pair(y,id));
}
int main(void) {
// freopen("data.in","r",stdin);
int n,m; while (~scanf("%d%d",&n,&m)) {
rep(i,1,n) G[i].clear(),d[i]=lxf[i]=0;
vec.clear();
rep(i,1,m) { cnt[i]=wjp[i]=0;
int x,y; scanf("%d%d",&x,&y);
vec.push_back(pair(x,y));
d[x]++; d[y]++;
}
rep(i,1,m) {
int x=vec[i-1].fi,y=vec[i-1].se;
if (x>y) std:: swap(x,y);
if (d[x]!=d[y]) {
if (d[x]>d[y]) std:: swap(x,y);
add_edge(x,y,i);
} else add_edge(x,y,i);
}
rep(i,1,m) {
int x=vec[i-1].fi,y=vec[i-1].se;
for (int j=0,_=G[x].size();j<_;++j) {
wjp[G[x][j].fi]=G[x][j].se;
lxf[G[x][j].fi]=i;
}
for (int j=0,_=G[y].size();j<_;++j) {
if (lxf[G[y][j].fi]==i) {
cnt[wjp[G[y][j].fi]]++;
cnt[G[y][j].se]++;
cnt[i]++;
}
}
}
LL ans=0;
rep(i,1,m) ans=(ans+1LL*cnt[i]*(cnt[i]-1)/2);
printf("%lld\n", ans);
}
return 0;
}