ARC099E. Independence

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

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

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

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

官方题解:

code
 
int main() {
  int n, m;
  scan(n, m);
  vv a(n, vi(n));
  rep (m) {
    int x, y;
    scan(x, y);
    --x, --y;
    a[x][y] = a[y][x] = 1;
  }
  vv 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 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 部分采用了滚动数组的技巧,要注意及时清空上一轮的状态。

posted @   Pat  阅读(208)  评论(0编辑  收藏  举报
编辑推荐:
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
阅读排行:
· 官方的 MCP C# SDK:csharp-sdk
· 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
· 提示词工程师自白:我如何用一个技巧解放自己的生产力
· 一文搞懂MCP协议与Function Call的区别
· 如何不购买域名在云服务器上搭建HTTPS服务
历史上的今天:
2016-11-21 HDU #2966 In case of failure
2016-11-21 K-D Tree
点击右上角即可分享
微信分享提示