ARC099E. Independence

时间:2019-11-21
本文章向大家介绍ARC099E. Independence,主要包括ARC099E. Independence使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

考虑一个子问题。给定无向图 $G$,如何判断能否将 $G$ 的点集分成两部分 $S$、$T$ 使得 $S$ 和 $T$ 导出的子图都是完全图?

这个问题把我难住了。解法是考虑 $G$ 的补图 $G'$,熟知 $G$ 中的完全子图对应于 $G'$ 中的独立集。

$G'$ 的点集能划分为两个独立集等价于 $G'$ 是二分图。

回到原问题。对于补图 $G'$ 的每个连通分量,二分图的两个点集是确定的。于是我们可以通过 DP 算出 $S$ 中可能有几个点。

官方题解:

代码

int main() {
  int n, m;
  scan(n, m);
  vv<int> a(n, vi(n));
  rep (m) {
    int x, y;
    scan(x, y);
    --x, --y;
    a[x][y] = a[y][x] = 1;
  }
  vv<int> g(n);
  rng (i, 0, n) {
    rng (j, 0, i) {
      if (!a[i][j]) {
        g[i].pb(j);
        g[j].pb(i);
      }
    }
  }
  vi vis(n);
  int c1, c2;
  vpii num;
  function<void(int)> dfs = [&](int u) {
    FOR (v, g[u]) {
      if (!vis[v]) {
        vis[v] = -vis[u];
        if (vis[v] == 1) {
          ++c1;
        } else {
          ++c2;
        }
        dfs(v);
      } else if (vis[v] != -vis[u]) {
        println(-1);
        exit(0);
      }
    }
  };
  rng (i, 0, n) {
    if (!vis[i]) {
      vis[i] = 1;
      c1 = 1, c2 = 0;
      dfs(i);
      num.eb(c1, c2);
    }
  }
  vi dp(n + 1);
  dp[0] = 1;
  int limit = 0;
  FOR (p, num) {
    down (i, limit, 0) {
      if (dp[i]) {
        dp[i] = 0; // 这里容易错。少了这一句就错了。
        dp[i + p.first] = 1;
        dp[i + p.second] = 1;
      }
    }
    limit += max(p.first, p.second);
  }
  int ans = INT_MAX;
  rng (i, 0, n + 1) {
    if (dp[i]) {
      chkmin(ans, i * (i - 1) / 2 + (n - i) * (n - i - 1) / 2);
    }
  }
  println(ans);
  return 0;
}

以上实现在 DP 部分采用了滚动数组的技巧,要注意及时清空上一轮的状态。

原文地址:https://www.cnblogs.com/Patt/p/11905410.html