Search on the blog

2012年1月7日土曜日

SRM528 DIV2 1000 Mosquitoes

直線状を移動する複数の蚊を効率的に殺す方法を考えるゲーム。

 時間がfixなら、端点のパターンをすべて試して最適なのを選ぶだけ。時間を選ぶのが難しいが、最適解において、ある2匹の蚊の距離は2Rになっていると仮定してよい。もし最適解において両端の蚊の距離が2R未満だったとしても、時間の経過とともに蚊は拡散していくのであるポイントで両端の蚊の距離は2Rになるからである。拡散しない場合(相対速度が一定)場合は、t=0のときに計算しているのでOK。

 自力では全く解けませんでした。蚊が時間の経過とともにある部分に密集していき、そのあとは拡散していくというようなイメージは浮かんだので、三分探索みたいなことをするのかなーと思ったら全く違った。この問題のように、”ある区間内とかある範囲内に何かを収めたい”というような問題の場合は、同じような思考が使える場合がよくあると思う。(四角形の中にあると言われたら、少なくとも2つの点は辺に接していると仮定していいとか。)最適解があって、そこから最適性を崩すことなく解を上手く動かすことで最適解にある仮定を設定することができ効率的な探索ができる、という考え方はしっかり身に付けたい。

const double EPS = 1e-9;
class Mosquitoes {
public:
    int getMaximum(vector<int> xInit, vector<int> v, int R) {
        int N = xInit.size();
        int ret = 0;
        vector<double> pos(N);

        // t = 0
        REP(i, N) pos[i] = xInit[i];
        sort(ALL(pos));
        REP(p, N) FOR (q, p, N) {
            if (pos[q] - pos[p] <= 2*R+EPS)
                ret = max(ret, q-p+1);
        }

        REP(i, N) REP(j, N) if (i != j){
            if (v[i] == v[j]) continue;

            // t = time when the distance between mosquito[i] and mosquito[j] = 2*R
            double t = 1.0 * (xInit[i]-xInit[j]-2*R) / (v[j] - v[i]);
            if (t < EPS) continue;

            REP(k, N) pos[k] = xInit[k] + v[k] * t;
            int cnt = 0;
            REP(k, N) {
                if (pos[j] <= pos[k] + EPS && pos[k] <= pos[i] + EPS)
                    ++cnt;
            }
            ret = max(ret, cnt);
        }

        return ret;
    }
};


 

0 件のコメント:

コメントを投稿