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

Автор Quercitron, 12 лет назад, По-русски

Мои программы на C# с dfs получают Runtime Error, видимо из-за переполнения стека.

Стандартный размер стека у треда в C# -- 1 МБ. Из-за этого программа без изменения размера стека падала на крупных тестах как на сервере, так и у меня локально.

Я прочитал, что новому треду при создании можно попытаться задать максимальный размер. Я увеличил его до 100 МБ, и это решило проблему локально, но на сервере решение продолжает падать. Возможно на сервере не хватает прав на увеличения стека.

Подскажите, пожалуйста, как мне справиться с этой проблемой.

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

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

Избавляйтесь от рекурсии. На codeforces стек у C# не увеличить.

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

    Объясните "синему" (мне) как обходить граф в глубину без рекурсии.

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

      Моделировать ручной стек.

    • »
      »
      »
      12 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится +15 Проголосовать: не нравится
      stack<int> s;
      int first[maxn];//первая не обработанная вершина
      bool edge[maxn][maxn];//матрица смежности
      int color[maxn];//цвета вершин
      const int white=0,gray=1,black=2;
      s.push(start);//start - стартовая вершина
      while(!s.empty()){
      	if( color[s.top()] != white ){
      		s.pop();
      		continue;
      	}
      	color[s.top()]=gray;
      	for(int i=first[s.top()];i<n;i++){//перебираем исходящие ребра
      		first[s.top()]=i+1;//помечаем, что обработали i-тую вершину
      		if( edge[s.top()][i] && color[i]==white ){
      			s.push(i);//вместо вызова dfs(i)
      			i=first[s.top()]-1;//теперь обрабатывается другая вершина, i ставится в начало
      		}
      	}
      	color[s.top()]=black;
      	s.pop();
      }
      
      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится +1 Проголосовать: не нравится

        BFS же, не?

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

          Это DFS, если заменить stack на queue будет BFS.

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

        А можете написать реализацию, где при обходе в глубину для вершины вычисляется параметр исходя из таких же параметров сыновей, для конкретности поиск числа потомков для каждой вершины с помощью обхода в глубину (не рекурсивная реализация)?

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

          Тем-же шаманством делаем топологическую сортировку, и находим число потомков начиная с листьев.

      • »
        »
        »
        »
        12 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        UPD. Гонево какое-то.

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

        Что это в принципе dfs — разумеется, да. Что он имеет все свойства рекурсивного dfs — разумеется, нет!!!

        Присваивание color[s.top()]=black; происходит ДО!!! обработки потомков в дереве dfs. И, например, проверку ацикличности (только сказать "да, цикл есть" или "нет, цикла нету"), в рекурсивном виде имеющую вид

        Procedure DFS_cycles(v);
        var u;
        Begin
          st[v]:=1; 
          for (u : v -> u) do (*перебираємо у змiннiй u всi вершини, куди йдуть дуги з вершини v*)
            if st[u]=0 then 
              DFS_cycles(u)
            else
              if st[u]=1 then
                CYCLE!!! ;
          st[v]:=2;
        End;
        

        трудно перевести в вышеупомянутый dfs вида while(!mystack.empty) { ... }

        Так что прав Shaykhutdinov-T-I, просящий написать прочие подробности реализации, а не минусующие его.

        Лично я вот знаю только один способ — более точно эмулировать рекурсивный dfs, храня в стеке (структуре данных) не просто вершины, а пары "какая вершина; какой по порядку её сосед уже рассмотрен".

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

          Спасибо, исправил.

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

            Что-то я не верю, что такие изменения действительно решили проблему...

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
          Rev. 5   Проголосовать: нравится +4 Проголосовать: не нравится

          UPD. Сам дурак.

          Вариант с покраской вершин (например, для того же поиска циклов):

          stack < int > s;
          int color[maxn];
          int first[maxn];
          bool edge[maxn][maxn];
          const int white = 0, grey = 1, black = 2;
          
          s.push(start);
          while (!s.empty()){
          	int from = s.top;
          	if (color[from] == white || color[from] == grey && first[from] < n){	//вершина непомеченна, или еще не из всех ее потомков запускался dfs
          		color[from] = grey;
          		boolean check = false; // имеется ли соседняя непомеченная вершина
          		for (int to = first[from]; to < n; ++to){ // запускаем dfs из всех необработанных соседей вершины
          			if (edge[from][to] && color[to] == white){
          				q.push(to);
          				first[from] = to + 1;
          				check = true;
          				break;
          			}
          		}
          		if (!check){
          			first[from] = n + 1;
          		}
          	}else{ // вершина помеченна, значит мы в нее пришли уже на выходе из рекурсии из потомков
          		// делаем все, что надо делать после выхода dfs из потомков вершины
          		
          		color[from] = black;
          		s.pop();
          	}
          }
          
          • »
            »
            »
            »
            »
            »
            12 лет назад, # ^ |
            Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

            UPD: это ответ на правку 2, следующие ещё не читал.

            Согласен, это тоже можно привести к правильному виду (именно привести, см., например, http://ideone.com/pUkoq ; так как было — неправильно). Я в общем-то и не утверждал, будто необходимо хранить текущую рассматриваемую вершину. Я утверждал, что ранее предложенные развёртывания рекурсии в цикл с использованием вместо программного стека структуры данных стек не умели различать три ситуации:

            1. вершина ещё вообще никак не исследована, в неё ещё не вошли

            2. в вершину вошли, но не вышли (продолжается рассмотрение подграфа, достижимого из неё)

            3. уже произошёл откат рекурсии через эту вершину

            (Например, есть граф с рёбрами 1->2, 1->3 и 2->3. Если мы уже посещали вершину 3 через 1->2->3, а потом ещё раз посетили через 1->3, это никоим образом не цикл.). Так что (1) от (2 и 3) надо отличать, чтоб принимать решение, надо ли именно тут продолжать поиск. (2) от (1 и 3) надо отличать, чтоб видеть действительно ли прямо сейчас обнаружен цикл.

            Спасибо за указание способа, как это всё же можно сделать.

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

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

            Например, орграф имеет n-1 дугу, все вида 1->i при i от 2 до n: предложенный Вами способ нарастит размер стека до n, хотя ни рекурсия ни точная её эмуляция так делать не будут.

            Так что они скорее альтернативные, каждый имеет достоинства и недостатки.

    • »
      »
      »
      12 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Через стэк. UPD: блин, надо обновлять страничку перед тем, как комментировать -_-

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

    Если нельзя увеличить размер стека, то это печаль Не для того я решаю задачи по СП, чтобы писать дфс без рекурсии

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

      Не для того я решаю задачи по СП, чтобы получать WA.

»
12 лет назад, # |
  Проголосовать: нравится +2 Проголосовать: не нравится

Подниму старую тему. Вопросы по С#:

  1. Можно ли как-то увеличить размер стека для рекурсии? (моделировать стек не вариант, т.к. другие языки имеют преимущество)
  2. Как насчет поддержки SortedSet i BigInteger? (добавить в строку компиляции dmcs вместо gmcs)
»
6 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Во время работы c# от Microsoft проблемы со стеком не было, и вот она опять появилась