Submission #53280106


Source Code Expand

#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;

const double INF = 1e18;
int n,m;
double eps,delta;
const int MAX_T = 5000;
const double M = 100000.0;
const int PARTICLE_SIZE = 4000;
const double POINT_BUFFER = 2000.0;


class Xorshift {
    public:
        Xorshift(uint32_t seed): x_(seed) {
            // assert(seed);
        }

        uint32_t randrange(uint32_t stop) {
            // [0, stop)
            // assert(stop > 0);
            next();
            return x_ % stop;
        }

        uint32_t randrange(uint32_t start, uint32_t stop) {
            // [start, stop)
            // assert(start < stop);
            next();
            return start + x_ % (stop - start);
        }

        uint32_t randint(uint32_t a, uint32_t b) {
            // [a, b]
            // assert(a <= b);
            return randrange(a, b + 1);
        }

        double random() {
            // [0.0, 1.0]
            next();
            return static_cast<double>(x_) * (1.0 / static_cast<double>(UINT32_MAX));
        }

        double uniform(double a, double b) {
            // [a, b] or [b, a]
            return a + (b - a) * random();
        }

    private:
        void next() {
            x_ ^= x_ << 13;
            x_ ^= x_ >> 17;
            x_ ^= x_ << 5;
        }

        uint32_t x_;
};

class Timer {
    public:
        Timer() {
            begin();
            elapsed_time_ = 0.0;
        }

        void begin() {
            start_time_ = chrono::system_clock::now();
        }

        double get_time() {
            chrono::system_clock::time_point end_time = chrono::system_clock::now();
            elapsed_time_ = chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time_).count();
            elapsed_time_ *= 1e-9; // nanoseconds -> seconds
            return elapsed_time_;
        }

        double get_last_time() const {
            return elapsed_time_;
        }

        bool yet(double time_limit) {
            return get_time() < time_limit;
        }

        double progress(double time_limit) {
            return get_time() / time_limit;
        }

    private:
        chrono::system_clock::time_point start_time_;
        double elapsed_time_;
};

class P {
public:
    double x, y;

    // コンストラクタ
    P(double x = 0, double y = 0) : x(x), y(y) {}

    // 加算演算子のオーバーロード
    P operator+(const P& a) const {
        return P(x + a.x, y + a.y);
    }

    // 減算演算子のオーバーロード
    P operator-(const P& a) const {
        return P(x - a.x, y - a.y);
    }

    // スカラー乗算演算子のオーバーロード
    P operator*(double a) const {
        return P(x * a, y * a);
    }

    // 等価演算子
    bool operator==(const P& other) const {
        return (x == other.x) && (y == other.y);
    }

    // 不等価演算子
    bool operator!=(const P& other) const {
        return !(*this == other);
    }
    double dot(const P& a) const {
        return x * a.x + y * a.y;
    }

    double det(const P& a) const {
        return x * a.y - y * a.x;
    }

    double abs2() const {
        return dot(*this);
    }

    double abs() const {
        return sqrt(abs2());
    }

    static P gets(P cand, double lim){
        double now = cand.abs();
        P ret = cand * (lim / now);
        return ret;
    }

    // デバッグ用の出力演算子オーバーロード
    friend ostream& operator<<(ostream& os, const P& p) {
        return os << " " << p.x << " " << p.y << " ";
    }

    static double dist2_sp(const P& p1, const P& p2, const P& q) {
        if ((p2 - p1).dot(q - p1) <= 0.0) {
            return (q - p1).abs2();
        } else if ((p1 - p2).dot(q - p2) <= 0.0) {
            return (q - p2).abs2();
        } else {
            return dist2_lp(p1, p2, q);
        }
    }

    static double dist2_lp(const P& p1, const P& p2, const P& q) {
        double det = (p2 - p1).det(q - p1);
        return (det * det) / (p2 - p1).abs2();
    }

    static bool crs_sp(const P& p1, const P& p2, const P& q) {
        return (q - p1).dot(q - p2) <= 0.0;
    }

    static bool crs_lp(const P& p1, const P& p2, const P& q) {
        return (p2 - p1).det(q - p1) == 0.0;
    }

    static bool crs_ss(const P& p1, const P& p2, const P& q1, const P& q2) {
        auto sort = [](double a, double b) {
            return minmax(a, b);
        };

        auto [lp0, up0] = minmax(p1.x, p2.x);
        auto [lq0, uq0] = minmax(q1.x, q2.x);
        auto [lp1, up1] = minmax(p1.y, p2.y);
        auto [lq1, uq1] = minmax(q1.y, q2.y);

        if (up0 < lq0 || uq0 < lp0 || up1 < lq1 || uq1 < lp1) {
            return false;
        }
        return sig((p2 - p1).det(q1 - p1)) * sig((p2 - p1).det(q2 - p1)) <= 0
            && sig((q2 - q1).det(p1 - q1)) * sig((q2 - q1).det(p2 - q1)) <= 0;
    }

    static P proj(const P& p1, const P& p2, const P& q) {
        double d = (p2 - p1).abs2();
        if (d == 0.0) return p1;
        P r = p1 * d + (p2-p1) * (p2-p1).dot(q-p1);
        return P(r.x / d, r.y /d);
    }

    static P get_nearest(const P& p1, const P& p2, const P& q){
        if ((p2 - p1).dot(q - p1) <= 0.0) {
            return p1;
        } else if ((p1 - p2).dot(q - p2) <= 0.0) {
            return p2;
        } else {
            return P::proj(p1,p2,q);
        }

    }

    static P pi_ll(const P& p1, const P& p2, const P& q1, const P& q2) {
        double d = (q2 - q1).det(p2 - p1);
        if (d == 0.0) {
            return P(INF,INF);
        }
        P r = p1 * d + (p2 - p1) * (q2 - q1).det(q1 - p1);
        return P(r.x / d, r.y / d);
    }

    static int sig(double x) {
        if (x > 0) return 1;
        if (x < 0) return -1;
        return 0;
    }
};


double clamp(double x, double minV = -M+1, double maxV = M-1){
    if (x <= minV){
        return minV;
    }
    if (x >= maxV){
        return maxV;
    }
    return x;
}

double normal(double x, double mean, double stdDev) {
    double v = (x - mean) / stdDev;
    return exp(-0.5 * v * v);
}


Xorshift rng(998244353);
Timer timer;
double time_limit = 1.97;
mt19937 engine(998244353);




// PID制御器を表す構造体
struct PID {
    double kp, ki, kd;
    P integral, prev_error;
    int last_turn;

    PID(double kp, double ki, double kd, int last_turn) : kp(kp), ki(ki), kd(kd), integral(), prev_error(),last_turn(last_turn) {}

    static PID new_with_default(int last_turn=-1) {
        return PID(0.2, 5.8174518156417054e-05, 1.6,last_turn);
    }

    P update(const P& pos, const P& target, int turn) {
        P error = target - pos;
        integral = integral + error;
        P derivative = (error - prev_error) * 0.6 ;//(1.0/(turn -last_turn));
        prev_error = error;
        last_turn = turn;

        return error * kp + integral * ki + derivative * kd;
    }
};


vector<P> ps;
vector<bool> finished(10);

P position;
P velocity;
vector<pair<P,P>> walls;

void Input() {
    cin >> n >> m >> eps >> delta;
    double x,y;
    cin >> x >> y;
    position = P(x,y);
    velocity = P(0,0);
    ps.resize(n);
    for (int i = 0; i < n; i++){
        double x,y;
        cin >> x >> y;
        ps[i] = P(x,y);
        
    }
    walls.resize(m+4);
    for (int i = 0; i < m; i++){
        double x1,y1,x2,y2;
        cin >> x1 >> y1 >> x2 >> y2;

        walls[i] = {P(x1,y1),P(x2,y2)};
    }
    walls[m] = {P(-M,-M),P{M,-M}};
    walls[m+1] = {P(M,-M),P{M,M}};
    walls[m+2] = {P(M,M),P{-M,M}};
    walls[m+3] = {P(-M,M),P{-M,-M}};

    m += 4;

};

// 座標などの情報を管理
// 接触判定や tsp によるパスなども求める
struct Graph {
    vector<vector<double>> points_dists;
    vector<vector<vector<int>>> points_roots;
    vector<P> path_points;
    vector<pair<P,P>> walls;
    int path_points_num;
    double wall_buffer;

    bool need_update_path = true;
    vector<int> target_path_roots;
    int target_path_ind = 0;
    P target;

    Graph() : target_path_ind(0) {}
    Graph(vector<P> ps, vector<pair<P,P>> walls, double wall_buffer) : walls(walls), path_points(ps),wall_buffer(wall_buffer){
        build();
    }

    void build(){

        // for (int i = 0; i < n; i++){
        //     for (int j = 0; j < m-4; j++){
        //         auto [p1,p2] = walls[j];

        //         auto q = P::get_nearest(p1,p2,path_points[i]);
        //         P dif = path_points[i] - q;
        //         P buf = P::gets(dif,1.0);

        //         cout << "# p = " << path_points[i] << " wall = " << j << " q = " << q << endl;
        //         if (!hit_wall(path_points[i]-buf,q+buf)){
        //             cout << "# succeed p = " << path_points[i] << " wall = " << j << " q = " << q << endl;

        //             path_points.push_back((path_points[i]+q) * 0.5);
        //         }
        //     }
        // }

        // for (int i = 0; i < m-4; i++){
        //     auto [p1,p2] = walls[i];

        //     for (int j = 0; j < m-4; j++){
        //         if (i == j) continue;
        //         auto [np1,np2] = walls[j];

        //         if (np1 != p1 && np2 != p1){
        //             auto q = P::get_nearest(np1,np2,p1);
        //             P dif = p1 - q;
        //             P buf = P::gets(dif,1.0);
        //             if (!hit_wall(p1-buf,q+buf)){
        //                 path_points.push_back((p1+q) * 0.5);
        //             }
        //         }
                
        //         if (np1 != p2 && np2 != p2){
        //             auto q = P::get_nearest(np1,np2,p2);
        //             P dif = p2 - q;
        //             P buf = P::gets(dif,1.0);
        //             if (!hit_wall(p2-buf,q+buf)){
        //                 path_points.push_back((p2+q) * 0.5);
        //             }
        //         }
        //     }
        // }
        // 壁から線分方向に buffer だけ離した場所に頂点を作る
        for (int i = 0; i < m-4; i++){
            auto [p1,p2] = walls[i];
            
            P dif = p2 - p1;
            P buf = P::gets(dif,wall_buffer);
            path_points.push_back(p2 + buf);
            path_points.push_back(p1 - buf);
        }

        path_points_num = path_points.size();

        points_dists.resize(path_points_num);
        points_roots.resize(path_points_num);
        for (int i = 0; i < path_points_num; i++){
            points_dists[i].resize(path_points_num,INF);
            points_roots[i].resize(path_points_num);
        }

        // 壁に当たらない頂点間を辺で結ぶ
        for (int i = 0 ; i < path_points_num; i++){
            for (int j = 0; j < i; j++){
                if (hit_wall(path_points[i],path_points[j])) continue;

                // double d = (path_points[i]-path_points[j]).abs();
                double d = calc_edge_weight(path_points[i],path_points[j]);
                points_dists[i][j] = d;
                points_roots[i][j].push_back(j);
                points_dists[j][i] = d;
                points_roots[j][i].push_back(i);
            }
        }

        // ワーシャルフロイドで頂点間の最短距離とその時に通過する頂点集合を求めておく
        for (int k = 0; k < path_points_num; k++){
            for (int i = 0; i < path_points_num; i++){
                for (int j = 0; j < path_points_num; j++){
                    if (points_dists[i][k] == INF || points_dists[k][j] == INF) continue;
                    if (points_dists[i][j] <= points_dists[i][k] + points_dists[k][j]) continue;

                    points_dists[i][j] = points_dists[i][k] + points_dists[k][j];
                    points_roots[i][j].clear();
                    for (auto pos : points_roots[i][k]){
                        points_roots[i][j].push_back(pos);
                    }
                    for (auto pos : points_roots[k][j]){
                        points_roots[i][j].push_back(pos);
                    }
                }
            }
        }
        for (int i = 0; i < path_points_num; i++){
        cout << "# dist from = " << i << endl;
        cout << "# ";
        for (int j = 0; j < path_points_num; j++){
            cout << points_dists[i][j] << " ";
        }
        cout << endl;
    }

    }

    // 線分が壁にぶつかるかの判定 当たるなら true
    bool hit_wall(P p1, P p2){
        bool ok = false;
        for (int i = 0; i < m; i++){
            if (P::crs_ss(p1,p2,walls[i].first,walls[i].second)) ok = true;
        }
        return ok;
    }

    // p1 から p2 の線分で ポイントを通過するか 通過するなら true
    bool hit(P p1, P p2, int i, double d = 1e6){
        return P::dist2_sp(p1,p2,path_points[i]) <= d;
    }

    double calc_wall_distance(P p1, P p2){
        double dist = INF;
        for (int i = 0; i < m; i++){
            dist = min(dist,P::dist2_sp(walls[i].first,walls[i].second,p1));
            dist = min(dist,P::dist2_sp(walls[i].first,walls[i].second,p2));
            dist = min(dist,P::dist2_sp(p1,p2,walls[i].first));
            dist = min(dist,P::dist2_sp(p1,p2,walls[i].second));
        }
        return dist;
    }
    double calc_edge_weight(P p1, P p2){
        double dist = (p1 - p2).abs();
        double wall_dist = calc_wall_distance(p1,p2);
        if (wall_dist < POINT_BUFFER){
            dist *= 1.0 + 5e-4 * eps * log2((POINT_BUFFER / max(wall_dist,1.0)));
        }
        return dist;

    }

    // p1 から dir 方向で最も近い壁との距離 必ず見つかる
    double nearest_wall(P p1, P dir){
        double dist = INF;
        P p2 = p1 + dir;
        for (int i = 0; i < m; i++){
            P cand = P::pi_ll(p1,p2,walls[i].first,walls[i].second);
            if (abs(cand.x - INF) < 1e-8) continue;;
            if ( P::sig(dir.det(walls[i].first-p1)) * P::sig(dir.det(walls[i].second-p1)) <= 0 && (cand-p1).dot(dir) >= 0){
                double dcand = (cand-p1).abs();
                if (dist > dcand){
                    dist = dcand;
                }
            } 
        }
        return dist;
    }

    // 粒子の候補に対して dir 方向の計測を行った時に期待される 距離の分散/距離の平均, 大きいほど嬉しい 
    double get_direction_var(vector<pair<P,P>> &particle_candidate, P dir){

        vector<double> ds;
        long double ds_sum = 0;
        for (auto &c: particle_candidate){
            double d = nearest_wall(c.first,dir);

            if (abs(d - INF) < 1e-8){
                assert (false);
            }
            ds.push_back(d);
            ds_sum += d;
            
        }
        long double avg = ds_sum / ds.size();
        long double var = 0;
        for (auto d: ds){
            var += (d-avg) * (d-avg);
        }
        var /= ds.size();

        return sqrt(var)/avg;
    }

    // 現在位置から次の目標までに壁がある場合、 ポイントを通過した場合は tsp で 次の目標を決める
    void update_target_root(P position){

        if (need_update_path == false){
            if (hit_wall(position,target)){
                need_update_path = true;
            }
        }

        if (need_update_path == false) return ;
        need_update_path = false;
        target_path_roots.clear();
        target_path_ind = 0;

        // pid = PID::new_with_default(turn-1);

        vector<double> dists(path_points_num,INF);
        vector<vector<int>> paths(path_points_num);
        priority_queue<pair<double,int>> h;
        for (int i = 0; i < path_points_num; i++){
            if (hit_wall(position,path_points[i])) continue;
            dists[i] = (position-path_points[i]).abs();
            h.push({-dists[i],i});
            paths[i].push_back(i);
        }

        while (!h.empty()){
            auto [d,now] = h.top();
            h.pop();
            for (int nex = 0; nex < path_points_num; nex++){
                double nd = -d + points_dists[now][nex];
                if (nd < dists[nex]){
                    dists[nex] = nd;
                    h.push({-nd,nex});
                    paths[nex].clear();

                    for (auto pos : paths[now]){
                        paths[nex].push_back(pos);
                    }
                    for (auto pos : points_roots[now][nex]){
                        paths[nex].push_back(pos);
                    }
                }
            }
        }
        int is_end = 0;
        int n2 = 1<<n;
        for (int i = 0; i < n; i++){
            if (finished[i]) is_end |= 1<<i;
        }

        pair<int,int> empty = {-1,-1};
        vector<vector<double>> dp(n,vector<double>(n2,INF));
        vector<vector<pair<int,int>>> par(n,vector<pair<int,int>>(n2,empty));

        for (int i = 0; i < n; i++){
            if (finished[i]) continue;
            dp[i][is_end|1<<i] = dists[i];
        }
        for (int bi = 0; bi < n2; bi++){
            for (int i = 0; i < n; i++){
                if (dp[i][bi] == INF) continue;
                for (int ni = 0; ni < n; ni++){
                    if (bi >> ni & 1) continue;
                    if (points_dists[i][ni] == INF) continue;
                    int nbi = bi | 1 << ni;
                    int ndist = dp[i][bi] + points_dists[i][ni];
                    if (ndist < dp[ni][nbi]){
                        par[ni][nbi] = {i,bi};
                        dp[ni][nbi] = ndist;
                    }
                }
            }
        }
        double mi = INF;
        pair<int,int> last;
        for (int i = 0; i < n; i++){
            if (dp[i][n2-1] == INF) continue;

            if (mi > dp[i][n2-1]){
                mi = dp[i][n2-1];
                last = {i,n2-1};
            }
        }

        while (true){
            auto p = par[last.first][last.second];
            if (p != empty){
                last = p;
                continue;
            }
            target_path_roots = paths[last.first];
            target = path_points[target_path_roots[0]];
            break;
        }
    
        cout << "# new targets path" << endl;
        cout << "# ";
        for (auto ind : target_path_roots){
            cout << ind << " ";
        }
        cout << endl;
    }

    void update_targets(P position, P velocity){
        if (need_update_path) return ;
        if (target_path_roots[target_path_ind] >= n || finished[target_path_roots[target_path_ind]]){
            if (hit(position,position+velocity,target_path_roots[target_path_ind])){
                target_path_ind++;
                target = path_points[target_path_roots[target_path_ind]];

            }
        }
    }

};

struct ParticleFilter {
    P position;
    P velocity;
    vector<pair<P,P>> particle_candidate;
    int particle_num;
    double sigma;

    
    ParticleFilter() : particle_num(PARTICLE_SIZE){}
    ParticleFilter(vector<pair<P,P>> particle_candidate, int particle_num) : particle_candidate(particle_candidate),particle_num(particle_num){
        update_current_state();
    }

    void update_current_state(){

        position = P();
        velocity = P();
        sigma = 0;
        for (auto &[np,nv] : particle_candidate){
            np.x = clamp(np.x);
            np.y = clamp(np.y);
            position = position + np;
            velocity = velocity + nv;
        }
        position = position * (1.0 / particle_candidate.size());
        velocity = velocity * (1.0 / particle_candidate.size());

        sigma = 0;
        for (auto &[np,nv]: particle_candidate){
            sigma += (np - position).abs2();
        }
        sigma /= particle_candidate.size();
        sigma = sqrt(sigma);
    }

    // 壁に当たったら速度を 0 にする
    void reset_velocity(){
        for (auto &cand: particle_candidate){
            cand.second = P(0,0);
        }
    }

    // パーティクルに速度分の変化を反映
    void position_update(){
        for (auto &cand: particle_candidate){
            cand.first = cand.first + cand.second;
        }
    }

    // パーティクルの不足分を補充する
    void fill_particle(vector<pair<P,P>> &nparticle_candidate){
        swap(particle_candidate,nparticle_candidate);
        while (particle_candidate.size() < particle_num){
            particle_candidate.push_back(particle_candidate[rng.randrange(particle_candidate.size())]);
        }
    }

    // パーティクルに加速クエリを反映
    void apply_accel(P accel){
        for (auto &c: particle_candidate){
            c.second = c.second + accel;
        }
    }

    // パーティクルに計測クエリを反映
    // 確率による重み付きで更新する
    void apply_measurement(P measure, Graph &graph){

        double res;
        cin >> res;

        cout << "# measurement result = " << res << endl;

        vector<double> probs;
        for (auto &cand: particle_candidate){
            double d = graph.nearest_wall(cand.first,measure);
            double alpha = res / max(1e-9,d);
            probs.push_back(max(normal(alpha,1.0,delta),1e-18));
        }

        discrete_distribution weighted(probs.begin(),probs.end());

        vector<pair<P,P>> nparticle_candidate;

        for (int _ = 0; _ < particle_num; _++){
            nparticle_candidate.push_back(particle_candidate[weighted(engine)]);
        }

        swap(particle_candidate,nparticle_candidate);

    }
    
    // 行動後の結果による更新
    pair<int,int> update_from_result(Graph &graph){
        
        mt19937 gen(998244353);
        normal_distribution<double> normal_dist(0.0,eps);

        int c,h;
        cin >> c >> h;
        cout << "# c = " << c << " h = " << h << endl;

        vector<bool> new_finished(n);

        if (h){
            for (int i = 0 ; i < h; i++){
                int x;
                cin >> x;
                new_finished[x] = true;
            }
        }

        vector<pair<P,P>> saved = particle_candidate;

        // アクションの結果と一致する候補を風の影響も踏まえて生成する
        int empty = 0;
        for (int _ = 0; _ < 10; _++){
            for (auto &cand : particle_candidate){
                double r1 = normal_dist(engine);
                double r2 = normal_dist(engine);
                cand.second.x += r1;
                cand.second.y += r2;
            }

            // 壁と当たるかの判定が結果と一致するか
            vector<pair<P,P>> nparticle_candidate;
            for (auto &cand: particle_candidate){
                if (graph.hit_wall(cand.first,cand.first+cand.second) == c){
                    nparticle_candidate.push_back(cand);
                }
            }

            if (nparticle_candidate.size()){
                fill_particle(nparticle_candidate);

            } else{
                particle_candidate = saved;
                empty++;
                continue;  
            }

            // 壁に当たったなら速度を 0 にして完了
            if (c == 1){

                reset_velocity();

                for (int i = 0; i < n; i++){
                    if (new_finished[i]) finished[i] = true;
                }

                return {c,h};

            } else{
                // 壁に当たってないなら h の通過判定が一致するかを確認

                position_update();

                bool ok = true;

                for (int i = 0; i < n; i++){
                    if (finished[i]) continue;

                    nparticle_candidate.clear();
                    // 頂点の通過判定が結果と一致するか
                    for (auto &cand: particle_candidate){
                        if (graph.hit(cand.first-cand.second,cand.first,i) == new_finished[i]){
                            nparticle_candidate.push_back(cand);
                        }
                    }

                    if (nparticle_candidate.size()){
                        fill_particle(nparticle_candidate);
                    } else{
                        particle_candidate = saved;
                        ok = false;
                        break;
                    }
                }
                if (!ok){
                    empty++;
                    continue;
                }
                // 通過判定も一致したのでリターン
                for (int i = 0; i < n; i++){
                    if (new_finished[i]) finished[i] = true;
                }
                return {c,h};
            }
        
        }
        // 全滅した
        for (int i = 0; i < n; i++){
            if (new_finished[i]) finished[i] = true;
        }
        // 壁に当たってたら今の候補をランダムでバラす
        if (c == 1){
            for (auto &cand: particle_candidate){
                cand.first.x += 2e4 * rng.uniform(-1.0,1.0);
                cand.first.y += 2e4 * rng.uniform(-1.0,1.0);
                cand.second = P(0,0);
            }
            
        } else{
            // 壁に当たってないなら速度は反映する
            position_update();

            // 通過判定があったらその近くにいたことにする
            for (int i = 0; i < n; i++){
                if (new_finished[i]){
                    for (auto &cand: particle_candidate){
                        cand.first = ps[i] + cand.second;
                    }

                }
            }
        }
        
        
        cout << "# empty = " << empty << endl;

        if (h || particle_num != particle_candidate.size()) return {c,h};

        // 全滅したら一時的に候補を増やす
        for (int i = 0; i < particle_num; i++){
            auto cand = particle_candidate[i];
            cand.first.x += 2e4 * rng.uniform(-1.0,1.0);
            cand.first.y += 2e4 * rng.uniform(-1.0,1.0);
            if (c == 0){
                cand.second.x *= rng.uniform(0.9,1.1);
                cand.second.y += rng.uniform(0.9,1.1);
            }
            particle_candidate.push_back(cand);
        }

        return {c,h};
    }
};


struct Solver{
    ParticleFilter particleFilter;
    Graph graph;
    int turn = 0;
    int hit_count = 0;

    PID pid = PID::new_with_default();

    // 終了判定
    void is_finish(){
        bool ok = true;
        for (int i = 0; i < n; i++){
            if (finished[i] == false) ok = false;
        }
        if (ok){
            exit(0);
        }
    }

    void accel_query(P a){
        a = P((int)a.x,(int)a.y);
        cout << "A " << (int)a.x << " " << (int)a.y << endl;

        particleFilter.apply_accel(a);
    }

    void measurement_query(P a){
        
        a = P((int)a.x,(int)a.y);
        cout << "S " << (int)a.x << " " << (int)a.y << endl;

        particleFilter.apply_measurement(a,graph);
    }

    P decide_next_target(){

        graph.update_target_root(particleFilter.position);
        return graph.target;
    }

    double max_velocity(double distance){
        if (eps == 0.0){
            return sqrt(0.9 * 2.0 * 500.0 * distance);
        } else{
            return sqrt(0.9 * 500 * distance);
        }
    }

    P decide_accel(P target){
        P dir = target - particleFilter.position;

        P acc = P::proj(P(),dir,particleFilter.velocity);
        bool approaching = dir.dot(acc) > 0.0;
        P fix = acc - particleFilter.velocity;

        if (fix.abs() > 498.0){
            return P::gets(fix,498.0);
        } else{
            double max_proceed = sqrt((500.0*500.0 - fix.abs2()));
            double proceed = max_velocity(dir.abs());
            if (approaching){
                proceed -= acc.abs();
            } else{
                proceed += acc.abs();
            }

            proceed = clamp(proceed,-max_proceed,max_proceed);

            return fix + P::gets(dir,proceed);
        }
    }

    void next_action(P target, double sigma, int turn){
        
        cout << "# target = " << target << endl;
        P a = decide_accel(target);

        // 条件を満たせば加速
        if (a != P() && (turn%2 == 0 || eps == 0.0 || sigma < 1000.0)){
            accel_query(a);
            return ;
        }

        // 計測の方向を最適化

        vector<P> cand;
        for (int i = 0; i < m; i++){
            if (i < m-4){
                cand.push_back(walls[i].first-particleFilter.position);
                cand.push_back(walls[i].second-particleFilter.position);
            } else{
                cand.push_back(walls[i].first-particleFilter.position);
            }
            cand.push_back(P::proj(walls[i].first,walls[i].second,particleFilter.position) - particleFilter.position);
        }
        vector<P> ncand;
        swap(cand,ncand);

        for (auto v: ncand){
            double d = v.abs();
            if (d > 1e5){
                v = v * (99998.0 / d);
            }
            v = P((int)v.x,(int)v.y);
            if (v.abs2() > 0.0){
                cand.push_back(v);
            }
        }
        vector<P> targets(2);

        if (false){//timer.get_time() >= 1.5){
            vector<double> scores(2,INF);

            for (auto dir: cand){
                double d = graph.nearest_wall(particleFilter.position,dir);
                if (d < scores[1]){
                    scores[1] = d;
                    targets[1] = dir;
                } else{
                    continue;
                }
                if (scores[1] < scores[0]){
                    swap(scores[1],scores[0]);
                    swap(targets[1],targets[0]);
                }
            }
        } else {
            vector<double> scores(2,-1.0);
            for (auto dir : cand){
                double d = graph.get_direction_var(particleFilter.particle_candidate,dir);
                if (d > scores[1]){
                    scores[1] = d;
                    targets[1] = dir;
                } else{
                    continue;
                }
                if (scores[1] > scores[0]){
                    swap(scores[1],scores[0]);
                    swap(targets[1],targets[0]);
                }
            }
        }
        cout << "# measure " << endl;
        if (rng.randrange(0,4) < 4){
            measurement_query(targets[0]);
        } else{
            measurement_query(targets[1]);
        }
    }

    void escape(int turn){
        for (int t = turn ; t < MAX_T; t++){
            cout << "A 0 0" << endl; 
        }
        exit(0);
    }

    void solve(){

        vector<pair<P,P>> candidate(PARTICLE_SIZE,{position,velocity});
        particleFilter = ParticleFilter(candidate,PARTICLE_SIZE);
        graph = Graph(ps,walls,POINT_BUFFER);
        
        for (int t = 0; t < MAX_T; t++){
            cout << "#turn = " << t << " eps = " << eps << " delta = " << delta << endl;
            // cout << "# ";
            // for (auto f : finished){
            //     cout << (int)f << " ";
            // }
            // cout << endl;
            // 全て通過したら終了
            is_finish();

            if (!timer.yet(time_limit)){
                escape(t);
            }

            // 推定情報を更新
            particleFilter.update_current_state();

            cout << "#p_pred = " << particleFilter.position << endl;
            cout << "#v_pred = " << particleFilter.velocity << endl;
            cout << "#sigma = " << particleFilter.sigma << endl;

  
            // 次の目標を決定
            P target = decide_next_target();

            // 行動を決定
            next_action(target,particleFilter.sigma,t);

            // 結果による更新
            auto [c,h] = particleFilter.update_from_result(graph);

            if (h){
                graph.need_update_path = true;
            }

            graph.update_targets(particleFilter.position,particleFilter.velocity);
        }

        cout << "#end at " << timer.get_time() << endl;
        
    }
};
int main() {
    Input();
    Solver solver = Solver();
    solver.solve();

    
    return 0;
}

Submission Info

Submission Time
Task B - Windy Drone Control (B)
User aaaaaaaaaa2230
Language C++ 23 (gcc 12.2)
Score 569002
Code Size 33207 Byte
Status AC
Exec Time 121 ms
Memory 5012 KiB

Compile Error

Main.cpp: In static member function ‘static bool P::crs_ss(const P&, const P&, const P&, const P&)’:
Main.cpp:180:14: warning: variable ‘sort’ set but not used [-Wunused-but-set-variable]
  180 |         auto sort = [](double a, double b) {
      |              ^~~~
Main.cpp: In constructor ‘Graph::Graph(std::vector<P>, std::vector<std::pair<P, P> >, double)’:
Main.cpp:321:23: warning: ‘Graph::walls’ will be initialized after [-Wreorder]
  321 |     vector<pair<P,P>> walls;
      |                       ^~~~~
Main.cpp:320:15: warning:   ‘std::vector<P> Graph::path_points’ [-Wreorder]
  320 |     vector<P> path_points;
      |               ^~~~~~~~~~~
Main.cpp:331:5: warning:   when initialized here [-Wreorder]
  331 |     Graph(vector<P> ps, vector<pair<P,P>> walls, double wall_buffer) : walls(walls), path_points(ps),wall_buffer(wall_buffer){
      |     ^~~~~
Main.cpp: In member function ‘void ParticleFilter::fill_particle(std::vector<std::pair<P, P> >&)’:
Main.cpp:687:42: warning: comparison of integer expressions of different signedness: ‘std::vector<std::pair<P, P> >::size_type’ {aka ‘long unsigned int’} and ‘int’ [-Wsign-compare]
  687 |         while (particle_candidate.size() < particle_num){
      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
Main.cpp: In member function ‘std::pair<int, int> ParticleFilter::update_from_result(Graph&)’:
Main.cpp:855:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<std::pair<P, P> >::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  855 |         if (h || particle_num != particle_candidate.size()) return {c,h};
      |                  ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Judge Result

Set Name test_ALL
Score / Max Score 569002 / 600000
Status
AC × 60
Set Name Test Cases
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt
Case Name Status Exec Time Memory
test_0000.txt AC 109 ms 4728 KiB
test_0001.txt AC 84 ms 4676 KiB
test_0002.txt AC 91 ms 4880 KiB
test_0003.txt AC 72 ms 4876 KiB
test_0004.txt AC 104 ms 4836 KiB
test_0005.txt AC 98 ms 4864 KiB
test_0006.txt AC 82 ms 4740 KiB
test_0007.txt AC 99 ms 4744 KiB
test_0008.txt AC 87 ms 4972 KiB
test_0009.txt AC 66 ms 4684 KiB
test_0010.txt AC 70 ms 4868 KiB
test_0011.txt AC 112 ms 4916 KiB
test_0012.txt AC 97 ms 4880 KiB
test_0013.txt AC 81 ms 4964 KiB
test_0014.txt AC 104 ms 4848 KiB
test_0015.txt AC 90 ms 4744 KiB
test_0016.txt AC 68 ms 5004 KiB
test_0017.txt AC 89 ms 4864 KiB
test_0018.txt AC 84 ms 4868 KiB
test_0019.txt AC 75 ms 4888 KiB
test_0020.txt AC 87 ms 4884 KiB
test_0021.txt AC 101 ms 4736 KiB
test_0022.txt AC 74 ms 4776 KiB
test_0023.txt AC 100 ms 4836 KiB
test_0024.txt AC 89 ms 4748 KiB
test_0025.txt AC 78 ms 4732 KiB
test_0026.txt AC 103 ms 4824 KiB
test_0027.txt AC 95 ms 4896 KiB
test_0028.txt AC 59 ms 4700 KiB
test_0029.txt AC 75 ms 4716 KiB
test_0030.txt AC 79 ms 4964 KiB
test_0031.txt AC 111 ms 4952 KiB
test_0032.txt AC 87 ms 4744 KiB
test_0033.txt AC 86 ms 4692 KiB
test_0034.txt AC 82 ms 4684 KiB
test_0035.txt AC 98 ms 4844 KiB
test_0036.txt AC 101 ms 4764 KiB
test_0037.txt AC 111 ms 5004 KiB
test_0038.txt AC 96 ms 4840 KiB
test_0039.txt AC 74 ms 4928 KiB
test_0040.txt AC 121 ms 4800 KiB
test_0041.txt AC 95 ms 5012 KiB
test_0042.txt AC 74 ms 4876 KiB
test_0043.txt AC 100 ms 4716 KiB
test_0044.txt AC 71 ms 4876 KiB
test_0045.txt AC 75 ms 4852 KiB
test_0046.txt AC 72 ms 4948 KiB
test_0047.txt AC 78 ms 4732 KiB
test_0048.txt AC 65 ms 4952 KiB
test_0049.txt AC 98 ms 4736 KiB
test_0050.txt AC 78 ms 4828 KiB
test_0051.txt AC 89 ms 4976 KiB
test_0052.txt AC 85 ms 4684 KiB
test_0053.txt AC 87 ms 4856 KiB
test_0054.txt AC 93 ms 4864 KiB
test_0055.txt AC 82 ms 4872 KiB
test_0056.txt AC 88 ms 4968 KiB
test_0057.txt AC 77 ms 4812 KiB
test_0058.txt AC 79 ms 4984 KiB
test_0059.txt AC 103 ms 4800 KiB