【HDU5952】Counting Cliques

題目大意:給定一個\(N\)個點,\(M\)條邊的無向圖,求圖中有多少個大小爲\(S\)的團。\(N \le 100,deg(i)\le 20,i\in [1,n]\)ios

題解:
考慮搜索。
須要肯定一種搜索順序,使得團的計數不重不漏。考慮枚舉團中最小編號的節點,且搜索狀態轉移中只能轉移到比當前團中編號最大的節點編號更大的點。c++

因爲\(N\)上限是100,可是每一個節點的度數很小,若直接用鄰接矩陣進行狀態轉移,複雜度較高,所以考慮創建鄰接表進行轉移。在判斷兩點是否存在邊時用鄰接矩陣快速判斷便可。spa

因爲編號由小到大進行轉移,所以對於建圖來講,每條邊能夠僅由編號小的點指向編號大的點,這樣轉移時又能夠省去一半的複雜度。code

搜索過程當中加入一個剪枝,即:當前團中的點加上後面能夠加的全部的點若是小於要求的團的大小,直接返回便可。ci

代碼以下it

#include <bits/stdc++.h>

using namespace std;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0), cout.tie(0);
  int T;
  cin >> T;
  while (T--) {
    int n, m, S;
    cin >> n >> m >> S;
    vector<vector<int>> adj(n);
    vector<vector<int>> mat(n, vector<int>(n));
    for (int i = 0; i < m; i++) {
      int x, y;
      cin >> x >> y;
      x--, y--;
      if (x > y) swap(x, y);
      adj[x].push_back(y);
      mat[x][y] = 1;
    }
    int ans = 0;
    vector<int> cyc;
    function<void(int)> dfs = [&](int x) {
      if ((int)cyc.size() == S) {
        ans++;
        return;
      }
      if (n - 1 - x < S - (int)cyc.size()) {
        return;
      }
      for (auto y : adj[x]) {
        bool ok = 1;
        for (auto z : cyc) {
          if (mat[z][y] == 0) {
            ok = 0;
            break;
          }
        }
        if (ok) {
          cyc.push_back(y);
          dfs(y);
          cyc.pop_back();
        }
      }
    };
    for (int i = 0; i < n; i++) {
      cyc.clear();
      cyc.push_back(i);
      dfs(i);
    }
    cout << ans << endl;
  }
  return 0;
}
相關文章
相關標籤/搜索