Блог пользователя ruban

Автор ruban, 14 лет назад, По-русски
Много раз пытался сдать 198B - прыжки по стенам. Вроде бы вполне осмысленное решение  -
  • код ниже — получает RE на 12 тесте. Но это не самое интересное — я поглядел 12 тест и
    обнаружил, что на том же тесте с длиной прыжка 56465 все нормально, а при длине 56466 — уже RE. Но и это не все. Мистика (для меня) состоит в том, что при чистке кода я обнаружил, что при удалении ненужных (нигде не используемых) переменных это самое число 56465 изменяется на несколько сотен. Я, естественно, понимаю, что один дурак может задать столько вопросов, что тысяча мудрецов не ответит, но все же, может кто что подскажет... (Для меня это — третья по счету задача с использованием рекурсии, а может и не в рекурсии дело). Заранее благодарен за подсказку.

program pr1;

{$APPTYPE CONSOLE} var n,k,i,j:longint; t:array[0..1,0..1000000] of int64; flag:boolean; marked: array [0..1,0..1000000] of boolean; sss:array[0..1] of string;

procedure dfs(num,pl,shag:longint); var i,p:longint;

begin if shag<pl then begin marked[num,pl]:=true; inc(shag); t[num,pl]:=shag; if not marked[1-num,pl+k] and (sss[1-num,pl+k]='-')and(pl<=n) then dfs(1-num,pl+k,shag); if not marked[num,pl+1] and (sss[num,pl+1]='-')and(pl<n+k) then dfs(num,pl+1,shag); if not marked[num,pl-1] and (sss[num,pl-1]='-')and(pl>1) then dfs(num,pl-1,shag); end;

end;

begin {assign (input,'input.txt');reset(input); assign (output,'output.txt'); rewrite(output); } readln(n,k); readln(sss[0]);readln(sss[1]); for i:=1 to 100000 do sss[0]:=sss[0]+'-'; for i:=1 to 100000 do sss[1]:=sss[1]+'-'; for i:=0 to n+k do begin t[0,i]:=1000000; t[1,i]:=1000000; end; t[0,1]:=0; dfs(0,1,0); flag:=false; for i:=n+1 to n+k do if (t[1,i]<1000000) or (t[0,i]<1000000) then begin flag:=true; end; if flag then write('YES') else write('NO'); close(output); end.

  • Проголосовать: нравится
  • -8
  • Проголосовать: не нравится

»
14 лет назад, скрыть # |
Rev. 3  
Проголосовать: нравится +6 Проголосовать: не нравится

Установите размер стека с помощью директивы {$MAXSTACKSIZE [размер в байтах]}. Я обычно ставлю 128МБ (правда, для Java).

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Кажется в Delphi есть директива MINSTACKSIZE (кроме MAXSTACKSIZE). Её и нужно установить

»
14 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится +3 Проголосовать: не нравится

Да в стеке дело, инфа соточка. Кинь как именно ты написал строку устанавливающую размер стека. А если ты действительно хочешь чтобы хоть кто то глянул на код, то приведи в божеский вид, так читать невозможно.

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Я пишу на С# и тоже всегда ловлю RE на DFSах. Вот здесь http://mirror.codeforces.com/blog/entry/79#comment-94622 я описал подробно почему это случается, и почему это нельзя пофиксить своими силами, видимо тут то же самое. Пока никакой реакции, так что могу посоветовать менять по возможности на BFS, писать нерекурсивную реализацию или учить что-то другое (плюсы)

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    А на Codeforces код разве запускается как частично доверенный? Мне казалось, что там делается так: клонируется виртуальная машина, на этом клоне запускается решение, а потом этот клон убивается. При такой конфигурации вроде бы вообще нет резона ограничивать "доверенность".

    ИМХО, дело в том, что на CF стоит не .NET Framework, а Mono.

    Я, кстати, через вкладку "Запуск" запускал исходники, читающие ключи реестра (чтобы узнать, какие процессоры стоят на серверах).

»
14 лет назад, скрыть # |
Rev. 6  
Проголосовать: нравится +16 Проголосовать: не нравится
Я нашел проблему:
1) Поставь в начале {M 10000000}
2) Забивай масив sss от 1 до 10^6.

1834680

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +2 Проголосовать: не нравится
    Огромное спасибо за реальную помощь - действительно сдалась. А теперь вопрос знающим людям - почему???? Что это за такие особенности языка, разобраться с которыми составило такую неслабую проблему! И напоследок - анекдот (желательно рассказывать, а не читать):

    Парень женился на старшей из трех сестер. Все безмерно рады. Через год приезжает — "Какое горе, жена померла". Ну ему по традиции дали в жены среднюю. Через год тот снова появляется — и прямо с порога : "Папаша , вы таки будете смяться, но Ваша Сонечка таки тоже померла! "

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +5 Проголосовать: не нравится

    Да, и чуть не забыл, с меня шоколадка. Будете у нас в Новосибирске на Всесибирской (где-то в ноябре )- тут же отдам. Вторая шоколадка тому, кто объяснит, в чем же дело. Важно ведь разобраться, чтобы в дальнейшем подобных проблем не было.

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Так вот!!! Дело вовсе не в стеке. Можно вообще про стек ничего не описывать. Достаточно просто к строке добавить не 10^5, а 198000 пробелов (195000 не хватает)- и все OK. Но почему??? Как все-таки работает рекурсия. Кто-нибудь понимает? Вроде бы нигде в проге к далеким элементам строки я не обращаюсь.

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    (sss[1-num,pl+k]='-') у тебя выходит за 100000 ...

    • »
      »
      »
      14 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится
      Не понял... У меня же к строке приписывается 100000 пробелов, а при DFSе я слежу, чтобы pl+k<=n+k (в коде - pl<=n). Так что вроде все нормально, по-моему.
      • »
        »
        »
        »
        14 лет назад, скрыть # ^ |
        Rev. 3  
        Проголосовать: нравится +2 Проголосовать: не нравится
        Оно у вас сразу вышло за границы и выбило рантайм, а потом уже проверило,'чувак' это делфи :)
        Попробуйте сразу проверить `pl<=n`, а потом уже делать следующие проверки, должно пройти ...
        

        UPD.Всё верно, прошло, вот этому подтверждение 1835200

      • »
        »
        »
        »
        14 лет назад, скрыть # ^ |
        Rev. 2  
        Проголосовать: нравится +6 Проголосовать: не нравится

        Omelianenko правильно говорит, что нужно вначале проверить, что не выходит за границы массива, а потом уже смотреть что там в массиве лежит.

        Суть в том, что оператор (A and B) работает по такому принципу: вначале проверяется A, если оно верно, то проверяется B, иначе B не проверяется, ибо смысла в этом нет. Поэтому важно вначале проверить выход за границы массива, чтобы если мы вышли, то второе условие не проверялось, если же переставить местами, то вначале мы проверяем ячейку массива, которой фактически нет, а дальше мы уже ничего не будем проверять, потому что у нас вылетит рантайм, ибо мы не можем проверять того чего нет.

        Оператор (A or B), кстати, тоже работает интересно: если A — true, то смысла проверять B нету, поэтому вот такой код хорошо сработает:

        t:=-1;
        for i:= 0 to n-1 do
        if (t<0 or a[t]<a[i]) then t:=i;
        

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

        И ещё хочу кое-что сказать. В С++ проверки за границы массива выключены по умолчанию (не знаю, можно ли их включить), поэтому если создать массив int a[10] (это массив int размера 10, с индексами от 0, то есть 0..9) и обращаться например к 20-му элементу массива a[20], то может так произойти, что рантайма не выскочит, хоть может и выскочить, зависит это от того, что будет храниться в ячейке памяти отстоящей на 20*4 байт от начала массива a, если будет ваша программа, то права на эту ячейку памяти у неё есть и она просто возьмёт оттуда данные (понятно, что совсем некорректные и ненужные и вообще чужие), и ещё хуже будет если она туда запишет данные, тем самым испортив какие-то чужие данные, если же эта ячейка памяти вообще не принадлежит вашей программе, то будет сгенерирован рантайм ошибка доступа. В паскале так тоже может происходить, но там по умолчанию включена проверка на выход за границы массива, но какая-то директива (не помню какая, можно погуглить) отключает эту проверку. Так что, ещё раз говорю, нужно быть осторожным с границами, иначе можно не просто рантайм получить, а вообще неадекватное поведение программы (например можно случайно в результате выхода за границы массива и обращения к ячейке памяти, в которой лежит например значение переменной n, от которой зависит текущий цикл, затереть это значение n и уйти в бесконечный цикл).

        • »
          »
          »
          »
          »
          14 лет назад, скрыть # ^ |
           
          Проголосовать: нравится +3 Проголосовать: не нравится

          Директива для отключения проверки выхода в паскале — {$R-}

        • »
          »
          »
          »
          »
          14 лет назад, скрыть # ^ |
           
          Проголосовать: нравится +1 Проголосовать: не нравится
          Еще раз спасибо за советы. Так вот, после экспериментов выяснилось, что обычный Delphi, со стандартными настройками при обращении к n+1-му  элементу массива все еще нормально (он=0), а к n+2 - уже RE. Со строкой все еще веселее - где-то 16000 элементов с ord=0, а дальше - RE. Именно эти 16000 элементов непонятного происхождения меня и сбили с толку - так бы я, пожалуй, легко сам обнаружил бы выход своей кривоватой проги за пределы строки.   Обычный же Pascal просто начинает обращаться к "левым" ячейкам памяти, что может привести к зависанию компа - этот эффект мне объяснили очень давно - лет двадцать. Капризность Delpi (оно и к лучшему) при работе с массивами тоже давно знакома. А вот столь странный эффект при работе со строкой обнаружен только сейчас. Буду знать. Еще раз всем спасибо за подсказки.
          • »
            »
            »
            »
            »
            »
            14 лет назад, скрыть # ^ |
             
            Проголосовать: нравится 0 Проголосовать: не нравится

            Может, строки в Delphi, как C++ vector-ы, автоматически ресайзятся, когда это необходимо? Вот и получается несколько нулей про запас в конце.

»
14 лет назад, скрыть # |
 
Проголосовать: нравится -7 Проголосовать: не нравится

Попробуй написать в самом верху кода {$M 128000000}