這東西其實就是一種暴力,只不過巧妙的是每一個環恰好統計了一次。
三元環計數推薦一篇博客,【科技】三元環計數,很詳細,很清楚。
每一個三元環之所以被算了一次,是因為一個三元環在新圖上必定只有一個點的出度為2,然后我們只在這個點上更新三元環數量。
然后我放了個代碼:
#define forE(i, x, y) for(int i = head[x], y; (y = e[i].to) && ~i; i = e[i].nxt)
In bool dcmp(int x, int y) {return d[x] == d[y] ? x > y : d[x] > d[y];}
In void calc_3()
{
for(int x = 1; x <= n; ++x)
{
forE(i, x, y) if(dcmp(x, y)) ++cnt[y];
forE(i, x, y) if(dcmp(x, y))
forE(j, y, z) if(dcmp(y, z) && cnt[z]) ++cir3[x], ++cir3[y], ++cir3[z];
forE(i, x, y) if(dcmp(x, y)) cnt[y] = 0;
}
}
四元環計數網上好想找不到,抄了神仙的代碼自己腦補了一下。 還是將圖按上述規則轉化成有向無環圖,然后對於每一個點$x$,遍歷他在新圖上的出邊,即走到的點為$y$,再遍歷$y$在**原圖**和$y$相鄰的點$z$,然后用上面代碼的dcmp函數判斷$x, z$,如果成立,說明找到了四元環的**一半**,那么用$z$上已經記錄的“半個”四元環個數更新$x, y, z$,然后在$z$上記錄這又多了一個“半個”四元環。 但這樣會導致先找到的“半個”四元環沒有和后面的“半個”四元環匹配上,因此我們還要按上述方法再遍歷一遍$x, y, z$,同時更新每一個節點上的四元環數量。 按這種方法遍歷一定會保證每一個四元環只被算過一次,但證明我還是沒太想明白。 ```c++ In void calc_4() { for(int x = 1; x <= n; ++x) { forE(i, x, y) if(dcmp(x, y)) forE(j, y, z) if(dcmp(x, z)) { int& v = cnt[z]; cir4[x] += v, cir4[y] += v, cir4[z] += v; ++v; } forE(i, x, y) if(dcmp(x, y)) forE(j, y, z) if(dcmp(x, z)) cir4[y] += (--cnt[z]); } } ```