Linear world POJ2674

投稿日: 更新日:

問題:http://poj.org/problem?id=2674

問題

NN人の人が長さLLの数直線上に並んでいる。また、全ての人は速さVVで進む。ii番目の人は名前はNAMEi\text{NAME}_iで位置POSi\text{POS}_iからDIRi\text{DIR}_iで示された方向へ進む。

人は他の人に出会うと、反対方向へ進みます。

最後に落ちる人の名前と時間をもとめてください。

解法

いくつかのステップに分けて考える。

1.最後に落ちる時間と方向

一旦名前を求めることを忘れる。出会った時、反対方向を向いて進むというのは有名問題「Ants」のようにすれ違ったとみなせばよい。従って、正の方向に進むひとなら、(LPOS)/V(L-POS)/V時間、負の方向に進むひとならL/VL/V時間かかることになる。この中から最大の値が、求める時間となる。

2.最後に落ちるのは左右どちらか?

正の向きをpp、負の向きをnnとする。

先ほど、求めた最大の時間が(LPOS)/V(L-POS)/Vの値、つまり正の向きに進む人であれば、最後に落ちるのはpp側。反対に、POS/VPOS/Vの値であれば、nn側となる。

3.各人々は左右どちらから落ちるのか?

人がA1,A2,A3,...ANA_1, A_2, A_3, ... A_Nと並んでいる。実際はすれ違っているのではなく、ぶつかった瞬間からどちらも反対方向に進むためこの並びは変わらない。

各人々がppに落ちる、nn側に落ちるとした時、必ずn1,n2,...ni,p(i+1),...pNn_1, n_2, ... n_i, p_{(i+1)}, ...p_Nのように全てのnnは左に、全てのppは右に集まる。なぜならばp,np, nのようになると、右に進む人は左に進む人にぶつかり、右に落ちれないという不整合が生じるからである。

また、ぶつかればそれぞれのp,np, nを交換しているだけなので、ppnnの数は変わらない。よって、nnの数をNnN_nとすると、前半NnN_n人はnn側から落ちる人、それ以外の後半はpp側から落ちる人となる。

4.最後に落ちる人の名前を求める

2で最後に落ちるのがn,pn, pどちらかが判明しているので、pp側であれば3で求めたpp側の人々のうち最もLLから離れている人。nn側であればnn側の人々のうち00から最も離れている人となる。

実装

変数is_positiveで最後に落ちるのがpp側かnn側かを記録している。

出力のフォーマットに注意する。

#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <algorithm>
using namespace std;

struct Person {
    char dir;
    double pos;
    string name;
};

void solve(int n){
    double l, v;
    cin >> l >> v;
    vector<Person> ps(n);
    for(int i = 0;i < n; ++i){
        cin >> ps[i].dir >> ps[i].pos >> ps[i].name;
        ps[i].dir = tolower(ps[i].dir);
    }

    double ans_time = -1;
    double is_positive;
    for(int i = 0;i < n; ++i){
        if(ps[i].dir == 'p'){
            double t = (l - ps[i].pos) / v;
            if(t > ans_time){
                ans_time = t;
                is_positive = true;
            }
        }else{
            double t = ps[i].pos / v;
            if(t > ans_time){
                ans_time = t;
                is_positive = false;
            }
        }
    }

    int cnt_p = 0, cnt_n = 0;
    for(int i = 0;i < n; ++i){
        if(ps[i].dir == 'p'){
            cnt_p++;
        }else{
            cnt_n++;
        }
    }

    int name_i;
    if(is_positive){
        name_i = n - cnt_p;
    }else{
        name_i = cnt_n-1;
    }

    printf("%13.2f %s\n", floor(ans_time*100)/100, ps[name_i].name.c_str());

}

int main(){
    ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n;
    cin >> n;
    while(n != 0){
        solve(n);
        cin >> n;
    }
    return 0;
}

書いた人

profile_image

お茶の葉

物理とプログラミングが好きな人