競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 328E

ABC328E

解法

BitDP による全探索. \(N = 8, M = \frac{N(N-1)}{2}\) の最大ケースで 辺の選び方は\({}_{M}C_{N-1} \leq \frac{25^7}{7!} = 1,211,015\)通り であるから間に合う. 辺の取り方を \(s \in 2^{M}\) から選べばよい.
別のbitDPとして,頂点の選び方に対するbitDPがある. \(s \in 2^N\)に対して,新しい頂点を追加する. そのとき,辺が張られている物だけを追加する. ただし,暫定的なコストの最小が,最終的な最小になるとは限らない. よって,コストの集合をもっておく.

\(dp_{s} := s \in 2^N\) におけるコストの集合

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

// bitDP: edge
int main() {
  ll n,m,k;
  cin >> n >> m >> k;
  vector<tuple<ll,ll,ll>> ed(m);
  rep(i,m){
    ll a,b,c; cin >> a >> b >> c;
    --a, --b;
    ed[i] = {a,b,c};
  }

  ll ans = 8e15;
  rep(s,1LL<<m){
    if(pcntll(s) != n-1) continue;

    UnionFind<ll> uf(n);
    ll cost = 0;
    rep(i,m) if(s>>i&1){
      auto [a,b,c] = ed[i];
      uf.merge(a,b);
      cost += c;
    }

   
    if(uf.size(0) == n){
      chmin(ans, cost%k);
    }
  }
  cout << ans << endl;
  return 0;
}

// bitDP: vertex
int main() {
  ll n,m,k;
  cin >> n >> m >> k;
  vvll co(n, vll(n, INFL));
  rep(i,m){
    ll a,b,c; cin >> a >> b >> c;
    --a, --b;
    co[a][b] = c;
    co[b][a] = c;
  }

  vector<set<ll>> dp(1LL<<n);
  rep(i,n) dp[1LL<<i].insert(0);

  rep(s,1LL<<n) rep(i,n) if(!(s>>i&1)){
    rep(j,n) if(s>>j&1){
      if(co[i][j]!=INFL){
        for(auto x: dp[s]){
          dp[s|(1LL<<i)].insert*1{
    chmin(ans, x);
  }
  cout << ans << endl;
 
  return 0;
}

*1:x + co[i][j])%k);

        }
      }
    }
  }

  ll ans = INFL;
  for(auto x:dp.back(