HDU5952Counting Cliques

Posted wzj-xhjbk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU5952Counting Cliques相关的知识,希望对你有一定的参考价值。

题目大意:给定一个(N)个点,(M)条边的无向图,求图中有多少个大小为(S)的团。(N le 100,deg(i)le 20,iin [1,n])

题解:
考虑搜索。
需要确定一种搜索顺序,使得团的计数不重不漏。考虑枚举团中最小编号的节点,且搜索状态转移中只能转移到比当前团中编号最大的节点编号更大的点。

由于(N)上限是100,但是每个节点的度数很小,若直接用邻接矩阵进行状态转移,复杂度较高,因此考虑建立邻接表进行转移。在判断两点是否存在边时用邻接矩阵快速判断即可。

由于编号由小到大进行转移,因此对于建图来说,每条边可以仅由编号小的点指向编号大的点,这样转移时又可以省去一半的复杂度。

搜索过程中加入一个剪枝,即:当前团中的点加上后面可以加的所有的点如果小于要求的团的大小,直接返回即可。

代码如下

#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;
}

以上是关于HDU5952Counting Cliques的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5952 Counting Cliques(dfs)

HDU 5952 Counting Cliques -暴力

HDU - 5952 Counting Cliques (dfs)

HDU5952Counting Cliques

E - Counting Cliques HDU - 5952

HDU5952 Counting Cliques 暴搜优化