Re[14]: Время черепахи
От: Кодт Россия  
Дата: 03.07.15 13:22
Оценка:
Здравствуйте, olimp_20, Вы писали:

_>Всё так же "Неправильный ответ" за исключением 2ух тестов (предполагаю, что для єтих двух тестов n=0)


А можно как-нибудь разжиться тестами — хотя б и неполным набором?
Чтобы не на их сервер грузить, а локально поиграться.
Перекуём баги на фичи!
Re[15]: Время черепахи
От: olimp_20  
Дата: 03.07.15 17:05
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А можно как-нибудь разжиться тестами — хотя б и неполным набором?

К>Чтобы не на их сервер грузить, а локально поиграться.

сайт
Раздел "XIV Всероссийская олимпиада школьников по информатике"
Тесты жюри
Re: Время черепахи
От: Кодт Россия  
Дата: 05.07.15 16:56
Оценка:
Здравствуйте, olimp_20, Вы писали:

Написал на питончике, не заботясь о производительности, и сверил с эталонами.

Первая проблема, на которую налетел.
Когда вычисляю количество цветов, съеденных в прямом направлении, — погрешности вычисления выстреливают.
Тест номер 5.
Черепаха бежит "туда" за время 09:27.556, при том, что последний цветок распускается в 09:32.
Максимальная задержка на старте, таким образом, — 00:04.444.
Но из-за погрешностей, получается, что черепаха на прямом пути ест 0 цветов (т.е. даже последний цветок не ест), что противоречит определению максимальной задержки.
Квик-фикс: добавим к максимальной задержке "ещё немножко запасу", 0.1 минуты — всё равно же мы там занимаемся подбором, ничего страшного в небольшом расширении диапазона не случится.
Перекуём баги на фичи!
Re[2]: Время черепахи
От: olimp_20  
Дата: 05.07.15 18:53
Оценка:
Здравствуйте, Кодт, Вы писали:
И насколько Ваш код отличается от моего? Я просто уже "потерялся", что там еще можно придумать...
  Код
//----------------------------------------------
        int s = x[n-1];
    for(int i=1; i<n; i++) x[i] -= x[i-1];

    minutes time;
    
    minutes tlast = t[n-1];
    minutes wmin = 0.0, wmax = tlast;
    const minutes epsilon = 0.1;
    while(wmax-wmin > epsilon) {
        minutes wmed = (wmin+wmax)/2.0;
        time = F(wmed+0.1);
        if (time >= tlast)
            wmax = wmed;
        else
            wmin = wmed;
    }


    int iS = ceil(s*1.0/vmax);
    time += (n-cnt)*d+iS;

    int itime = ceil(time);
    int x2=itime/60;
    int y2=itime%60;
    printf("%02d:%02d\n", x2, y2);
//----------------------------------------------
minutes F(minutes w) {
    cnt=0;
    for (int i=0; i<n; ++i) { // включая последний цветок
        if (t[i] < w+x[i]/vmax){
            w += x[i]/vmax+d;
            cnt++;
        }
    }
Re[3]: Время черепахи
От: Кодт Россия  
Дата: 05.07.15 23:20
Оценка:
Здравствуйте, olimp_20, Вы писали:

_>И насколько Ваш код отличается от моего? Я просто уже "потерялся", что там еще можно придумать...


Естественно, что очень сильно отличается, потому что я ставлю над ним всякие опыты.
Самый простой пример
v = ... # скорость
d = ... # задержка на еду
xts = [(x0,t0), (x1,t1), ...] # список координат цветов (без вычитания времени)

n = len(xts)
xz, tz = xts[-1] if xts else 0.,0. # координаты последнего цветка

def eaten(t0) :
  # сколько цветов съедено за проход туда, при данной начальной задержке
  k = 0
  for xi,ti in xts:
    t = t0 + xi/v + k*d # момент прибытия черепахи к данному цветку
    if t >= ti:
      k += 1
  return k

def eaten_incrementally(t0) :
  k = 0
  t, x = t0, 0
  for xi,ti in xts:
    t, x = t+(xi-x)/v, xi # продвигаем черепаху во времени и пространстве
    if t >= ti:
      k += 1
      t += d
  return k

Две функции подсчёта. Делают одно и то же. Ошибки набегают по-разному. Это очень сильно влияет на результат Причём инкрементная, с бОльшей погрешностью, — считает лучше...

Думаю, что вообще надо от деления отказаться, и трансформировать все формулы, так, чтобы остаться в целых числах.
Перекуём баги на фичи!
Re[2]: Время черепахи
От: Chorkov Россия  
Дата: 07.07.15 10:41
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, olimp_20, Вы писали:


К>Написал на питончике, не заботясь о производительности, и сверил с эталонами.


К>Первая проблема, на которую налетел.

К>Когда вычисляю количество цветов, съеденных в прямом направлении, — погрешности вычисления выстреливают.

Избежать ошибок округления, проще всего перейдя к целым числам.
Единица измерения времени равная 1/v минут, нам это обеспечит.
Re[3]: Время черепахи
От: Кодт Россия  
Дата: 07.07.15 14:01
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Избежать ошибок округления, проще всего перейдя к целым числам.

C>Единица измерения времени равная 1/v минут, нам это обеспечит.

Это само собой. Просто это — одна из граблей, которая в задаче существует.
Перекуём баги на фичи!
Re[3]: Время черепахи
От: olimp_20  
Дата: 07.07.15 19:05
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Избежать ошибок округления, проще всего перейдя к целым числам.

Понятно, например так:
  код
#include <stdio.h>
#include <vector>
#include <math.h>
using namespace std;

typedef double minutes;//тип double необходим для поиска задержки на старте и правильного вычисления результата!!!
bool F( minutes w );//возвращает количество пройденных цветов и значений true, если черепаха дошла до цветка N и съела его

int n;
int vmax, d;
vector<int> x;
vector<int> t;

int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);

    
    scanf("%d%d%d", &vmax, &d, &n);

    if(n==0)
    {
        printf("00:00\n");
        return 0;
    }

    x.assign(n,0);
    t.assign(n,0);
    int hh, mm;
    for(int i=0; i<n; ++i) {
        scanf("%d %d:%d", &x[i], &hh, &mm);
        t[i]=hh*60+mm;
    }


    int s = x[n-1];//длина пути в одну сторону

    minutes tlast = t[n-1];//время последнего цветка

        //алгоритм бинар. поиска: мин. задержка на старте wmin, чтобы успеть к проростанию цветка N
    minutes wmin = 0, wmax = tlast;
    minutes wait;
    while(wmax-wmin>0.1) {//условие для действительных чисел
        wait = (wmin+wmax)/2;    
        if(F(wait))
            wmax = wait;
        else
            wmin = wait;        
    }

    //Важно: в формуле использовать wmin - не wait, и не wmax - все-таки вычисляется мин. значение для задачи
    double dtime = wmin + n*d + s*2.0/vmax; //сума чисел типа double увеличивает дробную часть так, что позволяет правильно выполнить ceil(dtime)

    int itime = ceil(dtime);
    int x2=itime/60;
    int y2=itime%60;
    printf("%02d:%02d\n", x2, y2);

    return 0;
}

bool F( minutes w )
{
    isN = false;
    int cnt=0;//количество посещенных и съеденных цветов
    for (int i=0; i<n; ++i) { // включая последний цветок
        int time = w*vmax + x[i] + cnt*d*vmax;  // момент прибытия черепахи к данному цветку
        if (time >= t[i]*vmax){//проверка на достижимость цветка к моменту его проростания
            cnt++;
            if(i==n-1) isN = true;//если среди посещенных и съеденных (не обязательно все подряд)
                                      //есть N-ый цветок
        }
    } 
    return isN;
}

Всем спасибо за помощь
Отредактировано 08.07.2015 14:49 olimp_20 . Предыдущая версия . Еще …
Отредактировано 08.07.2015 11:32 olimp_20 . Предыдущая версия .
Отредактировано 08.07.2015 6:15 olimp_20 . Предыдущая версия .
Отредактировано 08.07.2015 6:12 olimp_20 . Предыдущая версия .
Отредактировано 07.07.2015 21:16 olimp_20 . Предыдущая версия .
Отредактировано 07.07.2015 21:13 olimp_20 . Предыдущая версия .
Отредактировано 07.07.2015 21:10 olimp_20 . Предыдущая версия .
Отредактировано 07.07.2015 21:09 olimp_20 . Предыдущая версия .
Отредактировано 07.07.2015 19:08 olimp_20 . Предыдущая версия .
Re: Время черепахи
От: Кодт Россия  
Дата: 13.07.15 18:25
Оценка: 2 (1)
Здравствуйте, olimp_20, Вы писали:

Ещё немного поигрался.

0. Процедура забега: черепаха ползёт вперёд, останавливаясь только на тех цветках, которые распустились; затем тупит на последнем цветке (вообще-то, это запрещённый режим); затем ползёт назад и ест все оставшиеся цветки.
Напишем функцию fulltime(s), вычисляющую время полного забега туда-сюда, при условии стартовой задержки s.

1. Напишем предикат ok(s) показывающий, что при забеге вперёд черепаха не тупит.
Очевидно, что для sz = xz/v-tz, где xz,tz — координаты последнего цветка, ok(sz) заведомо истинно.

Очевидно, что если ok(s) выполняется, то fulltime(s) = s + n*d + 2*xz/v = s + D, где D — константа, D = n*d+2*xz/v
— тупим только на старте (во время забегов не тупим, на последнем цветке тоже не тупим)
— тратим время на съедение всех цветков, неважно, в первой или второй фазе
— тратим время собственно на забег туда-обратно

Если же ok(s) ложно, то fulltime(s) = s + D + stop(s)
т.е. у нас появляется некоторое время ожидания на последнем цветке, зависящее от стартовой задержки.
График stop(s) круче графика CONST-s — он состоит из ряда ступенек: проходя через каждый распустившийся цветок, stop(s) скачком уменьшается (т.к. черепаха сидит на этом цветке — и поэтому будет меньше тупить в конце).

Поэтому абсолютный минимум fulltime(s) наблюдается в точке smin = min [s for s in range(0,sz+1) if ok(s)]
— на участке not ok(s) функция ступенчато уменьшается
— на участке ok(s) линейно растёт

2. Функция ok(s) имеет форму ровно одной ступеньки, и именно поэтому точку smin можно найти бисекцией.

В таком виде у меня все тесты прошли.
Моя предыдущая ошибка состояла в том, что я искал не min s | ok(s), а min s | num(s)==num(sz), где num(s) — количество цветков, съеденных по направлению туда.
Очевидно, что этот предикат — более сильное условие, т.е. если он выполняется, то ok(s) тоже выполняется. Поэтому с ним мы находим более позднюю точку.
Перекуём баги на фичи!
Re[13]: Время черепахи
От: Erop Россия  
Дата: 15.08.15 21:13
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Наша задача — как можно более рационально распорядиться временем до t[n-1].

На самом деле задача чуть тоньше. Может так оказаться, что выгодно приползти к последнему цветку раньше, чем t[n-1]+d, если мы при этом съедим больше цветов, чем если приползём к t[n-1]... То есть перебор таки есть, но из двух вариантов.

Дальше, по идее нам всё равно какие именно цветы есть по пути "туда", главное скока есть.
Так что можно "запустить кино обратно", ползти назад по времени от момента t[n-1] и от момента t[n-1]+d и смотреть какие из цветов мы успеваем скушать.
По идее это один проход по массиву...
В смысле два. Если оба два дают одно количество цветов, то ясно, что ответ тривиален. Если второй вариант даёт +1, то среди тех цветов, кого не успеваем скушать при походе к t[n-1] находим тот, кого меньше всего ждать. Эта дельта t и даст ответ.

Но можно всё сделать и за один, конечно же.
Просто "крутим кино назад", и считаем
1) Сколько цветов успеваем при этом съесть, если ползём к t[n-1]
2) При какой минимальной задержке можем съесть ещё один.

Ну и если (1) меньше d, то считаем по формуле с лишним заранее съеденным, а если нет, о без него.
В принципе, если эту дельту с самого начала инициализировать в d, то формулы совпадут и всё ещё упростится...
Ergo: думаю, что можно написать формулу для нескольких столбикой ёкселя, такую, что если в A будут позиции цветов, а в B времена их расцвета, то в Z1 будет время возвращения в домик.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 15.08.2015 23:59 Erop . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.