這東西其實就是一種暴力,只不過巧妙的時每個環剛好統計了一次。
三元環計數推薦一篇博客,【科技】三元環計數,很詳細,很清楚。
每個三元環之因此被算了一次,是由於一個三元環在新圖上一定只有一個點的出度爲2,而後咱們只在這個點上更新三元環數量。
而後我放了個代碼:html
#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\),同時更新每個節點上的四元環數量。
按這種方法遍歷必定會保證每個四元環只被算過一次,但證實我仍是沒太想明白。函數
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]); } }