競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 301E

ABC301E

5 sec, 1024 mb. 制約が 5 sec と長い.
大事な頂点の個数が少ない事を利用する. \(S, G, o\) が 20 個以下になるので,bit dp 可能. つまり,訪れた点の集合と時刻さえ分かれば,順番は関係ないということ.

実装: お菓子の置かれたマスの個数を \(c\) とする. お菓子のマスを \(0 , \cdots, c-1\), S のマスを \(c\) , G のマスを \(c+1\) とする.
前処理:

  • BFSにより,大事なマス同士の距離を求めておく. 始点を大事なマスとする BFS で, \(O(\,(c+2)5HW\,)\).
  • この結果を用いて,大事なマス同士のコストを求めておく.

後処理:
時刻が \(T\) 以下で辿り着けるマスのうち, \(x := \) (大事なマスを訪れた回数) \(- 2\) が最も多いものが答え. \(-2\) は,S,Gを除くため. \(x = pcntll(bitmsk)\) で求まる.

別解: 方針は同じだが,dp をするときに \( dp[bitmsk][vertex] = \{count, time\} \) の形で求める. \(time \leq T\) となる物だけ抽出しながら遷移する.

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

int main() {
  ll h,w,t; cin >> h >> w >> t;
  vector<string> a(h);
  cinv(a);

  ll c = 0;
  map<pll, ll> id;
  rep(i,h) rep(j,w){
    if(a[i][j] == 'o') {
      id[{i,j}] = c++;
    }
  }
  rep(i,h) rep(j,w){
    if(a[i][j] == 'S') {
      id[{i,j}] = c;
    }
    if(a[i][j] == 'G') {
      id[{i,j}] = c+1;
    }
  }
  ll n = c + 2;

  vvll cost(n, vll(n, INFL));

  // on original graph
  {
    auto bfs = [&](ll sx, ll sy) -> void {
      vvll dis(h, vll(w, INFL));
      vector<vector<bool>> vis(h, vector<bool>(w));
      queue<pll> que;

      auto push = [&](ll x, ll y, ll d) -> void {
        if(vis[x][y]) return;
        vis[x][y] = true;
        que.push({x,y});
        chmin(dis[x][y], d);
        if(id.find({x,y}) != id.end()){
          chmin(cost[id[{sx,sy}]][id[{x,y}]], d);
        }
      };

      push(sx, sy, 0);
      while(que.size()){
        auto [cx,cy] = que.front(); que.pop();
        ll d = dis[cx][cy];

        vll dx = {1,0,-1,0};
        vll dy = {0,1,0,-1};
        rep(i,4){
          ll nx = cx + dx[i];
          ll ny = cy + dy[i];
          if(!in(nx,h)) continue;
          if(!in(ny,w)) continue;
          if(a[nx][ny] == '#') continue;
          push(nx, ny, d + 1);
        }
      }

    };


    rep(x,h) rep(y,w) if(!(a[x][y] == '.' || a[x][y] == '#')){
      bfs(x,y);
    }
   
  }

  // on new graph
  {
    // dp : time
    vvll dp(1LL<<n, vll(n, INFL));

    dp[1LL<<c][c] = 0;
    rep(s,(1LL<<n)) rep(cu, n) if(s >> cu & 1){
     
      rep(ne, n) if(!(s >> ne & 1)){
        ll ns = s | (1LL<<ne);

        ll nt = dp[s][cu] + cost[cu][ne];
        // if(nt <= t)
          chmin(dp[ns][ne], nt);
      }
    }

    ll ans = -INFL;
    rep(s,(1LL<<n)) if(s >> (c+1) & 1){
      if(dp[s][c+1] <= t)
        chmax(ans, ll(pcntll(s)-2)); // 2 = {S,G}
    }
    if(ans < 0) ans = -1;
    cout << ans << endl;



  }


  return 0;
}