実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 272
問題概要
のマス目があり、上から
行目、左から
列目のマスを
と表す。各マスの状態は文字
で表され、
#
のときそのマスは机、.
のときそのマスは床である。床のマスは2つ以上存在することが保証される。
これから床のマスから異なる2マスを選び、加湿器を設置することにする。加湿器が設置されたとき、あるマス は加湿器があるマス
からのマンハッタン距離が
以下であるときに限り加湿される。ここで、加湿器が置かれた床のマスは必ず加湿されている。
加湿される床のマス の個数として考えられる最大値を求めよ。
制約
は整数。
考察
の制約が小さいので、全探索が使えそう。具体的には、以下のような処理となる。
- 床のマスを配列
floors
に格納しておく。 floors
の中から加湿器を設置するマスを2つ選ぶ。これをとする。
それぞれに対して、次の操作を行う。
floors
の各マスを走査し、(または
) とのマンハッタン距離が
以下ならカウンターを1増やす。
- カウンターをこれまでの最大値と比較・更新。
- 最終的な最大値を出力。
計算量としては、 の選択のすべての場合を行うのに
、
それぞれとすべての床マスとのマンハッタン距離の計算に
、合計
となるが、今回の制約下では十分高速である。
B問題にしてはfor
ループのネストが多めなので、適宜処理を別の関数に分割していった方が良さそう。
コード
#include <bits/stdc++.h> using namespace std; using Pair_int = pair<int, int>; #define all(x) (x).begin(), (x).end() // ======================================== // int dist(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); } int calc(const vector<Pair_int> &floors, int x1, int y1, int x2, int y2, int D) { set<pair<int, int>> cells; for (const auto &cell : floors) { if (dist(cell.first, cell.second, x1, y1) <= D) { cells.insert(cell); } } for (const auto &cell : floors) { if (dist(cell.first, cell.second, x2, y2) <= D) { cells.insert(cell); } } return cells.size(); } int main() { int H, W, D; cin >> H >> W >> D; vector<string> S(H); vector<Pair_int> floors; rep(i, 0, H) { cin >> S[i]; rep(j, 0, W) { if (S[i][j] == '.') { floors.emplace_back(i, j); } } } int ans = 0; int n = floors.size(); rep(i, 0, n) { rep(j, i + 1, n) { int x1 = floors[i].first, y1 = floors[i].second; int x2 = floors[j].first, y2 = floors[j].second; int cnt = calc(floors, x1, y1, x2, y2, D); chmax(ans, cnt); } } cout << ans << endl; }
実装時間: 10分