CodeForces1741G-Kirill and Company题解

\(\large\text{CodeForces1741G-Kirill and Company题解}\)

题面传送门(有翻译(由黄巨佬提供))

思路

预处理

因为 \(k\) 很小,所以可以先 bfs 预处理出家在 \(i(2\le i\le n)\) 的人能捎带上哪些集合的人,在表示集合时用一个 \(0\)\(2^k-1\) 的整数 \(j\) 表示,若 \(j\) 在二进质下的从小到大第 \(l\) 位是 \(1\),那么这个集合就包含第 \(l\) 的没车的人。

在 bfs 从 \(i\) 转移到 \(j\) 时,如果 \(i\) 能成为 \(1\)\(j\) 的最短路上的点,那么家在 \(i\) 的人能捎带上的人的集合家在 \(j\) 的人也能捎带上,注意集合里还要加上家在 \(j\) 点且没车的人。

预处理完后做 dp :
  • \(dp_{i,j}\) 表示前 \(i\) 个人是否能捎带上 \(j\) 集合里的所有人。
  • 转移(扩散型):
    • 如果第 \(i+1\) 个人没车,那么如果 \(dp_{i,j}=1\)\(dp_{i+1,j}=1\) 否则 \(dp_{i+1,j}=0\)
    • 如果第 \(i+1\) 个人有车,那么如果 \(dp_{i,j}=1\) 且第 \(i+1\) 个人回家的路上能捎带上集合 \(l\) 的人,则对于 \(j\)\(l\) 的并集 \(q\)\(dp_{i+1,q}=1\)
  • 在表示集合的时候,可以用预处理时的方法,那么 \(j\)\(l\) 的并集就是 \(j|l\)
答案

对于每个 \(dp_{tot,j}=1\)\(j\),输出 \(k\) 减去集合大小最大的 \(j\) 的集合大小。

时间复杂度

对于每个测试点

bfs

\(O((n+m)\cdot 2^k)\)

dp

\(O(tot\cdot 2^{2k})\)

\(O((n+m)\cdot 2^k+tot\cdot 2^{2k})\)

空间复杂度

对于每个测试点

\(O(n\cdot 2^k+tot\cdot 2^k)\)

代码(不建议在做出来之前看)

优美的码风

#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 1e4 + 1, kMaxS = 1 << 6;

int t, n, m, p[kMaxN], o, h[kMaxN], k, c[kMaxN], dp[kMaxN][kMaxS], ma;
bool a[kMaxN][kMaxS], f[kMaxN];
vector<int> b[kMaxN];
queue<int> q;

void R(int x, int l, int j) {
  if (j <= c[x]) {
    if (j < c[x]) {
      c[x] = j;
      q.push(x);
    }
    for (int i = 0; i < (1 << k); i++) {
      a[x][(i | p[x])] |= a[l][i];
    }
  }
}

int S(int x) {
  int ans = 0;
  for (; x; ans++, x -= (x & (-x))) {
  }
  return ans;
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  for (cin >> t; t--;) {
    cin >> n >> m;
    for (int i = 1, u, v; i <= m; i++) {
      cin >> u >> v;
      b[u].push_back(v), b[v].push_back(u);
    }
    cin >> o;
    for (int i = 1; i <= o; i++) {
      cin >> h[i];
    }
    cin >> k;
    fill(p + 1, p + n + 1, 0);
    fill(f + 1, f + o + 1, 0);
    for (int i = 1, a; i <= k; i++) {
      cin >> a;
      f[a] = 1;
      p[h[a]] += (1 << (i - 1));
    }
    fill(a[1], a[n] + kMaxS, 0);
    a[1][0] = 1;
    fill(c + 1, c + n + 1, n + 1);
    for (R(1, 0, 0); q.size(); q.pop()) {
      for (int i : b[q.front()]) {
        R(i, q.front(), c[q.front()] + 1);
      }
    }
    fill(dp[0], dp[o] + kMaxS, 0);
    dp[0][0] = 1;
    for (int i = 0; i < o; i++) {
      for (int j = 0; j < (1 << k); j++) {
        if (dp[i][j]) {
          if (!f[i + 1]) {
            for (int l = 0; l < (1 << k); l++) {
              if (a[h[i + 1]][l]) {
                dp[i + 1][j | l] = 1;
              }
            }
          } else {
            dp[i + 1][j] = 1;
          }
        }
      }
    }
    ma = 0;
    for (int i = 0; i < (1 << k); i++) {
      ma = max(ma, S(i) * dp[o][i]);
    }
    cout << k - ma << "\n";
    for (int i = 1; i <= n; i++) {
      b[i].clear();
    }
  }
  return 0;
}
posted @ 2023-08-24 17:19  nehcyx  阅读(38)  评论(1)    收藏  举报