Linear world POJ2674
投稿日: 更新日:
問題:http://poj.org/problem?id=2674
問題
人の人が長さの数直線上に並んでいる。また、全ての人は速さで進む。番目の人は名前はで位置からで示された方向へ進む。
人は他の人に出会うと、反対方向へ進みます。
最後に落ちる人の名前と時間をもとめてください。
解法
いくつかのステップに分けて考える。
1.最後に落ちる時間と方向
一旦名前を求めることを忘れる。出会った時、反対方向を向いて進むというのは有名問題「Ants」のようにすれ違ったとみなせばよい。従って、正の方向に進むひとなら、時間、負の方向に進むひとなら時間かかることになる。この中から最大の値が、求める時間となる。
2.最後に落ちるのは左右どちらか?
正の向きを、負の向きをとする。
先ほど、求めた最大の時間がの値、つまり正の向きに進む人であれば、最後に落ちるのは側。反対に、の値であれば、側となる。
3.各人々は左右どちらから落ちるのか?
人がと並んでいる。実際はすれ違っているのではなく、ぶつかった瞬間からどちらも反対方向に進むためこの並びは変わらない。
各人々がに落ちる、側に落ちるとした時、必ずのように全てのは左に、全てのは右に集まる。なぜならばのようになると、右に進む人は左に進む人にぶつかり、右に落ちれないという不整合が生じるからである。
また、ぶつかればそれぞれのを交換しているだけなので、との数は変わらない。よって、の数をとすると、前半人は側から落ちる人、それ以外の後半は側から落ちる人となる。
4.最後に落ちる人の名前を求める
2で最後に落ちるのがどちらかが判明しているので、側であれば3で求めた側の人々のうち最もから離れている人。側であれば側の人々のうちから最も離れている人となる。
実装
変数is_positive
で最後に落ちるのが側か側かを記録している。
出力のフォーマットに注意する。
#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;
}