LINUX.ORG.RU
ФорумTalks

Поиск всех путей на графе (Небольшой тест. Часть 2)

 


1

2

Только тем, у кого есть время. Есть однонапрвленный упорядоченный граф (надо найти все пути из a в z, но, видимо, программно):

a → b, c, d, z
b → d, e, f, z
c → d, e, f, z
d → e, f, z
e → f, z
f → g, h, j, z
g → h, i, j, z
h → i, j, k, z
i → j, k, l, z
j → k, m, z
k → l, n, o, z
l → m, z
m → n, o, z
n → o, z
o → p, z
p → q, z
q → r, z
r → s, z
s → t, u, z
t → u, v, z
u → v, w, z
v → w, z
w → x, y, z
x → y, z
y → z
z → (нет исходящих)

Свой результат пишу сразу ( даже не уверен, что 100% правильный, но все ж…): Все пути:

22061

Все пути в массивах. Вывод кода: https://filebin.net/ysidtdizjge50kjh

Код для проверки: https://gitflic.ru/project/dcc0/mix-c-89-php/blob?file=allways_more_20k.php



Последнее исправление: AnonymUser (всего исправлений: 7)
Ответ на: комментарий от firkax

Не сказать, что алгоритм тривиален, если честно. Три цикла и довольно непростой массив.

  • довльно хитрая конкатенанция.

Но по итерациям вроде я его разобрал. 1 цикл - идём по столбцу. 2 цикл - идем по строке. 3 цикл - обходим заново массив, в который все время добавляем новые пути. Строим пути пошагово. (на третьем цикле можно запутаться) Третий цикл перезапускам для каждого нового элемента второго цикла (когда идем по строке). Добавляем в ways новые индексы (взяты из строки). Внутрь этих индексов третьим циклом добавляем рёбра (строим пути).

Результат работы с пояснением итераций. Код сократил.

 == Идем по строке ====a Добавим новый индекс (конкатенация):  - a ->  Индексу newdot: ->  b Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - a ->  Индексу newdot: ->  c Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - a ->  Индексу newdot: ->  d Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - a ->  Индексу newdot: ->  f Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
        )

    [f] => Array
        (
            [af] => 119
        )

)

 Новая итерация второго цикла  == Идем по столбцу вниз====>\r\n  возврат в первый цикл  == Идем по строке ====b Добавим новый индекс (конкатенация):  - ab ->  Индексу newdot: ->  d Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
        )

    [f] => Array
        (
            [af] => 119
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - ab ->  Индексу newdot: ->  e Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
        )

    [f] => Array
        (
            [af] => 119
        )

    [e] => Array
        (
            [abe] => 9
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - ab ->  Индексу newdot: ->  f Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
        )

    [e] => Array
        (
            [abe] => 9
        )

)

 Новая итерация второго цикла  == Идем по столбцу вниз====>\r\n  возврат в первый цикл  == Идем по строке ====c Добавим новый индекс (конкатенация):  - ac ->  Индексу newdot: ->  d Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
            [acd] => 12
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
        )

    [e] => Array
        (
            [abe] => 9
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - ac ->  Индексу newdot: ->  e Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
            [acd] => 12
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
        )

    [e] => Array
        (
            [abe] => 9
            [ace] => 10
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - ac ->  Индексу newdot: ->  f Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
            [acd] => 12
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
            [acf] => 9
        )

    [e] => Array
        (
            [abe] => 9
            [ace] => 10
        )

)

 Новая итерация второго цикла  == Идем по столбцу вниз====>\r\n  возврат в первый цикл  == Идем по строке ====d Добавим новый индекс (конкатенация):  - ad ->  Индексу newdot: ->  eДобавим новый индекс (конкатенация):  - abd ->  Индексу newdot: ->  eДобавим новый индекс (конкатенация):  - acd ->  Индексу newdot: ->  e Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
            [acd] => 12
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
            [acf] => 9
        )

    [e] => Array
        (
            [abe] => 9
            [ace] => 10
            [ade] => 9
            [abde] => 14
            [acde] => 19
        )

)

 Новая итерация второго цикла Добавим новый индекс (конкатенация):  - ad ->  Индексу newdot: ->  fДобавим новый индекс (конкатенация):  - abd ->  Индексу newdot: ->  fДобавим новый индекс (конкатенация):  - acd ->  Индексу newdot: ->  f Печатаем массив ways после всех итерций третьего цикла Array
(
    [a] => Array
        (
            [a] => 0
        )

    [b] => Array
        (
            [ab] => 3
        )

    [c] => Array
        (
            [ac] => 7
        )

    [d] => Array
        (
            [ad] => 2
            [abd] => 7
            [acd] => 12
        )

    [f] => Array
        (
            [af] => 119
            [abf] => 11
            [acf] => 9
            [adf] => 6
            [abdf] => 11
            [acdf] => 16
        )

    [e] => Array
        (
            [abe] => 9
            [ace] => 10
            [ade] => 9
            [abde] => 14
            [acde] => 19
        )

)



AnonymUser
() автор топика
Ответ на: комментарий от firkax

Твой урезанный код (оставил для разбора):

<?php
$links = array(
    'a' => array('b' => 3, 'c' => 7, 'd' => 2, 'f' => 119),
    'b' => array('d' => 4, 'e' => 6, 'f' => 8),
    'c' => array('d' => 5, 'e' => 3, 'f' => 2),
    'd' => array('e' => 7, 'f' => 4),
    'e' => array('f' => 3),
    'f' => array(),
);

$from = 'a';
$to = 'f';

$i = 0;
/* если нужен список путей */
$ways = array($from => array($from => 0));

foreach ($links as $dot => $list) {
    $i++;
    print ' == Идем по строке ====';
    echo $dot . ' ';
    if (!isset($ways[$dot])) continue;
    $curways = $ways[$dot]; // пути до текущей точки

    foreach ($list as $newdot => $dist) {
        foreach ($curways as $way => $waydist) {
            echo "Добавим новый индекс (конкатенация): ";
            echo ' - ' . $way . ' -> ';
            $ways[$newdot][$way . $newdot] = $waydist + $dist;
            echo " Индексу newdot: ->  " . $newdot;
        }
        print ' Печатаем массив ways после всех итерций третьего цикла ';
        print_r($ways);
        print "\n";
        print " Новая итерация второго цикла ";
    }

    print ' == Идем по столбцу вниз====>';
    print '  возврат в первый цикл ';
}
?>

Сложность в том, что приходится работать все время с растущими индексами, некоторые из них пушутся заново, а в некоторые дописывается путь - в индекс индексов. На деле получаем «растущее дерево», почти, как рекурсивное. Но я не фанат рекурсии. Мне так с индексами не очень удобно работать. Но спасибо за код и пояснения.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)
Ответ на: комментарий от ugoday

Мне рекурсия не нравится. Она только запутывает. Алгоритму лучше быть очевидным: «по рельсам в одном направлении, до конечной станции». А рекурсия - что-то вроде езды задом наперёд с вилянием рулевым колесом.

Сколько циклов в твоём scheme?! Если их три, то всё то же самое.

Вряд ли есть способ обойти все пути менее, чем за три цикла.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 4)
Ответ на: комментарий от AnonymUser

Мне рекурсия не нравится.

Она от вас тоже не в восторге.

Алгоритму лучше быть очевидным

Рекурсивный обход дерева — самый естественный и человечный способ.

Сколько циклов в твоём scheme?!

o.O

ugoday ★★★★★
()
Ответ на: комментарий от AnonymUser

довольно непростой массив

Наоборот, он наоборот максимально простой - куда идём, как идём, длина пути.

довльно хитрая конкатенанция

Все конкатенации одинаковые - просто соединяем две строки.

firkax ★★★★★
()
Ответ на: комментарий от AnonymUser

некоторые из них пушутся заново, а в некоторые дописывается путь - в индекс индексов.

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

На деле получаем «растущее дерево», почти, как рекурсивное. Но я не фанат рекурсии.

Рекурсии тут нет. Через неё можно было бы сделать, но это не добавило бы никакой пользы.

firkax ★★★★★
()
Ответ на: комментарий от firkax
Не надо об этом думать, 

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

P.S.

Рекурсии нет, но очень напоминает. :)

Рекурсия вообще, конечно, может быть, полезная штука. Но мне напоминает такое: можно просто подняться на 10 этаж а можно сначала на второй, потом спуститься на первый, пототм подняться на 5, снова спуститься на первый… и так до 10 этажа.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

а можно сначала на второй, потом спуститься на первый, пототм подняться на 5, снова спуститься на первый… и так до 10 этажа.

Я уже говорил вам, что вы наркоман. С тех пор ничего не поменялось. Если вы дерево папок в файловой системе захотите обойти, как вы это сделаете? Зайдёте в директорию, посмотрите содержимое. Потом зайдёте в первую поддиректорию данной, потом в поддиректорию поддиректории. И так пока всё не посмотрите. Это рекурсивный обход дерева и с этим справляются даже самые малаграматные пользователи.

ugoday ★★★★★
()
#!/usr/bin/env lua

local input =
[[
a → b, c, d, z
b → d, e, f, z
c → d, e, f, z
d → e, f, z
e → f, z
f → g, h, j, z
g → h, i, j, z
h → i, j, k, z
i → j, k, l, z
j → k, m, z
k → l, n, o, z
l → m, z
m → n, o, z
n → o, z
o → p, z
p → q, z
q → r, z
r → s, z
s → t, u, z
t → u, v, z
u → v, w, z
v → w, z
w → x, y, z
x → y, z
y → z
z → (нет исходящих)
]]

local paths = { }

for start,list,val in input:gmatch('(%w)%s+→(.-)\n') do
    paths[start] = { }
    for v in list:gmatch('%s+(%w)') do
        if not paths[start][v] then
           paths[start][v] = v
        end
    end
    ---
    for k, p in pairs(paths) do
        for x,v in pairs(p) do
            if x == start  then
               p[x] = paths[start]
            end
        end
    end
end

local count = 0

local function trace(path,name)
    for k,v in pairs(path) do
        if k == 'z' then
           io.write(name..'z \n')
           count = count + 1
        else
           trace(v,name..k..' -> ')
        end
    end
end

trace(paths['a'],'')
print(count)
...
22061

Не сразу понял, долго тупил. Затем ещё дольше тупил почему у меня 51599 путей выходит, пока не понял что я ищу все пути от всех к z, а надо только от a к z

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

5 циклов вижу. Это только явных. Алогритм рабочий вроде. Довольно шустрый, время:

real	0m1,442s
user	0m0,373s
sys	0m0,435s

Хотя в php конкатенцаия, скорее всего, тоже через цикл организована. Т.е. все равно минимум 3 цикла + 1 или 2 функции нужно минимум для выполнения данного алгоритма .

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от AnonymUser

Это очень медленно. Вот, для сравнения:

scheme@(hello-lor)> ,time (define pz (list-paths "z"))
;; 0.006063s real time, 0.006021s run time.  0.000000s spent in GC.
scheme@(hello-lor)> (length pz)
$46 = 22061

Так что вам задание со звёздочкой: как вы будете параллелить свои циклы? На вопрос «а как твоя рекурсия распараллеливается,а?!». Отвечаю: с помощью reducer’ов.

ugoday ★★★★★
()
Ответ на: комментарий от ratvier

Сиквел не планировался. Мной по крайней мере.

Зачем трогать циклические графы?!

Мы уже вплотную подошли к задаче коммивояжера.

М.б. даже незаметно для себя ее решили. Частично, конечно.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от ugoday

Мухлюешь и не краснеешь =) Сделай вывод всех десятков тысяч полных путей, и считай время с момента старта интерпретатора, внешней утилитой, включая работу всего кода, разбор ввода, формирование данных для обхода, обход данных, а не выборочной части.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Кто вас учил тесты делать? (тут, по смыслу, должно стоять какое-то оскорбительное предоложение, но даже как-то ничего в голову не приходит).

Сделай вывод всех десятков тысяч полных путей

Чтобы смешать скорость алгоритма со скоростью работы терминала? Надеюсь, вы так шутите.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Я к тому что

Вот, для сравнения:

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

Кто вас учил тесты делать?
Чтобы смешать скорость алгоритма со скоростью работы терминала?

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

В любом случае, мы тут прикалываемся, а не на надутых щах.

но даже как-то ничего в голову не приходит

Конечно, я же пушистый няфка, это как пытаться оскорблять вомбата =) Хочешь поругаться, а получаются одни мимимишки ^.^

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Это не для сравнения, если хочешь сравнивать сделай аналогичную работу.

Так я всё сделал правильно. А если другая сторона допустила ошибку измерения, то это она должна свой косяк испрвлять.

Это всё относительно, запускать каждый всё должен у себя, ибо у нас железо разное.

При разнице в скорости в 250 раз, различиями в железе можно пренебречь.

P.S. Ну и так-то мой тезис не в том, что scheme быстрее php (вообще в этом не уверен и (если важна скорость вдруг, вы серьёзно ошиблись с выбором языков)). Главное, что я хочу показать: «выбор удобного представления данных радикально снижает сложность работы».

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Внял.

Ну и так-то мой тезис не в том, что scheme быстрее php

Есть chicken scheme, оно точно должно быть быстрее, быстрый алгоритм + быстрое его представление для исполнения и всё клёва

выбор удобного представления данных радикально снижает сложность работы

Ну, да. Самое простое (наверное) вообще будет ввод отформатировать в виде готовой Си структуры (при этом тулза форматирования выносится во вне, как просто утилитарная штука для перевода представления данных). А затем тупо (как у нас выше) протрассировать её рекурсией. И вся реализация сведётся тупо к 1 функции спуска a->next->next->…..->next->next->z.

Играться можно долго, при этом количество путей как по мне эт неинтересно, интересно получать сами пути, так как практической ценности больше, например можно в игре обозначить точки на карте, где игрок сражается с ботами, и вычислив пути, в зависимости от сложности ботов задавать им разные пути, и как следствие разное время прибытия на точку, или если промежуточные части имеют свою сложность преодоления, можно игроку выстраивать путь (блокируюя другие) который он должен пройти, при этом получается рогалик, карта одна, есть варианты достижения финала, и есть 100500 вариантов построения пути, каждый из которых уникальная комбинация, но с предсказуемым преодолением. Ну, а все пути от x до y это про как собрать 100% ачивок :)

Прошёл карту 22061 раз. Значит полностью прошёл игру хехе

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Есть chicken scheme, оно точно должно быть быстрее,

Потом придёт сишнек/растовик и надерёт скриптоте жопу. Чем соревноваться с ними в однопотоке, гораздо выгоднее сыграть в игру

На всякий вопрос найдётся ответ.
У нас есть TCO, у вас его нет.

Рекурсивный алогритм проще записывается и проще параллелится. Тут уже можно и нагнуть байтолюбов.

Прошёл карту 22061 раз. Значит полностью прошёл игру хехе

😱😱😱😱😱😱

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

😱😱😱😱😱😱

гы, а чего, было бы наполнение точек графа интересным и стыковались бы они произвольно друг с другом как эта плитка

И будет вполне себе рогалик, и не случайный, а просто оконечно вариантивный, который можно пройти, но сложно.

Рекурсивный алогритм проще записывается и проще параллелится. Тут уже можно и нагнуть байтолюбов.

Ну, если паралелить… Ну я бы не был так уверен, на маленьких графах типа такого, будет профит, всё можно если не в L2 так в L3 запихать если побайтобитодрочить и бодрое ядро в однопоток проявит себя очень хорошо. Распараллеливание всё же имеет свои накладные расходы. А вот на больших данных, например в таблице от 1000x1000 с множеством связей уже однопоток захлебнёся.

Но это надо экспериментировать и играться

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от ugoday

Пусть циклические алгоритмы медленнее (хотя не все), но они очевиднее. А все это «выкручивание наизнанку» оперативной памяти можно оставить академическим кругам. Пущай окодемики рекурсией развлекаются. Даешь народу циклические алгоритмы?! =)

https://ibb.co/kVJ60JRh

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Для вас великий человек лекцию прочитал. Очень рекомендую просмотреть (и законспектировать).

ugoday ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

На маленьких графах можно и без компьютера посчитать. Интересное начинается на больших размерах. И тут я купил процессор с 12 ядрами, пусть он считает на всех 12 ядрах. На подобных задачах можно получить почти линейное ускорение. Т.е. на порядок быстрее однопотока. А ради такого дела можно и расстараться.

ugoday ★★★★★
()
Ответ на: комментарий от AnonymUser

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от AnonymUser

Пущай окодемики рекурсией развлекаются. Даешь народу циклические алгоритмы?! =)

«Окодемики» и народ едины, ибо по-простому: рекурсия = цикл + стек.

quickquest ★★★★★
()
Ответ на: комментарий от firkax

Взял твой вариант и попросил deepai переписать на C. Переписал с кучей структур.

Сейчас взял свой относительно простой вариант и попросил deepai и alice переписать на C89. deepai не осилил. Брал вот этот: https://pastecode.ru/28ecf9/

А вот alice справилась, похоже. Её код компилируется и запускается. И интересно то, что на попыталась переписать без структур, использовала switch case:

#include <stdio.h>
#include <string.h>

/* Максимальное количество вершин в пути.
   Граф небольшой, 20 достаточно с запасом. */
#define MAX_PATH 20

/* Функция возвращает указатель на массив соседей для данной вершины.
   Вершины: 'a'..'f'. Возвращает NULL для неверной вершины. */
static const char *get_neighbors(char v) {
    switch (v) {
        case 'a': return "bcd";
        case 'b': return "def";
        case 'c': return "def";
        case 'd': return "ef";
        case 'e': return "f";
        case 'f': return "";
        default:  return NULL;
    }
}

/* Вспомогательная функция: найти индекс символа в строке.
   Возвращает -1, если не найден. */
static int str_index_of(const char *s, char c) {
    int i = 0;
    while (s[i] != '\0') {
        if (s[i] == c) return i;
        i++;
    }
    return -1;
}

int main(void) {
    /* Первый путь (из PHP-скрипта) */
    char path[MAX_PATH];
    int path_len = 0;

    /* Инициализация первого пути: a -> b -> d -> e -> f */
    path[path_len++] = 'a';
    path[path_len++] = 'b';
    path[path_len++] = 'd';
    path[path_len++] = 'e';
    path[path_len++] = 'f';

    /* Вывод первого маршрута */
    {
        int i;
        for (i = 0; i < path_len; i++) {
            if (i > 0) printf(", ");
            printf("%c", path[i]);
        }
        printf("\n");
    }

    int j = path_len - 1;

    while (j != 0) {
        char current_v = path[j - 1];
        const char *neighbors = get_neighbors(current_v);

        /* В PHP: $ar = search_val($x, $j, $arr); */
        /* Здесь neighbors — это аналог $ar */

        int key = str_index_of(neighbors, path[j]);

        /* if (isset($ar[$key + 1])) */
        if ((key != -1) && (neighbors[key + 1] != '\0')) {
            /* $x = array_slice($x, 0, $j); */
            path_len = j;

            /* array_push($x, $ar[$key + 1]); */
            path[path_len++] = neighbors[key + 1];

            /* Достраиваем путь до 'f', всегда беря первого (нулевого) соседа */
            while (1) {
                char last_v = path[path_len - 1];
                if (last_v == 'f') {
                    break;
                }
                const char *next_neighbors = get_neighbors(last_v);
                /* В PHP: search_new_val_for_push_int_x(...)[0] */
                if (next_neighbors[0] != '\0') {
                    path[path_len++] = next_neighbors[0];
                } else {
                    /* Если нет соседей, а мы не в 'f', дальше идти некуда.
                       В логике PHP это не обрабатывается явно, но предотвратим зацикливание. */
                    break;
                }
            }

            j = path_len;

            /* print_r($x); */
            {
                int i;
                for (i = 0; i < path_len; i++) {
                    if (i > 0) printf(", ");
                    printf("%c", path[i]);
                }
                printf("\n");
            }
        }

        j--;
    }

    return 0;
}


AnonymUser
() автор топика
Ответ на: комментарий от firkax

Брал вот этот твой. Урезал его максимум и попросил Алису переписать. В общем успешно, но километров кода вышло много:

 <?php
$links = array(
    'a' => array('b' => 3, 'c' => 7, 'd' => 2, 'f' => 119),
    'b' => array('d' => 4, 'e' => 6, 'f' => 8),
    'c' => array('d' => 5, 'e' => 3, 'f' => 2),
    'd' => array('e' => 7, 'f' => 4),
    'e' => array('f' => 3),
    'f' => array(),
);

$from = 'a';
$to = 'f';

/* если нужен список путей */
$ways = array($from => array($from => 0));

foreach ($links as $dot => $list) {


    if (!isset($ways[$dot])) continue;
    $curways = $ways[$dot]; // пути до текущей точки

    foreach ($list as $newdot => $dist) {
        foreach ($curways as $way => $waydist) {

            $ways[$newdot][$way . $newdot] = $waydist + $dist;

        }
    }
}
print_r($ways);
 ?>

И вот что ответила:

Важно сразу прояснить: C89 (ISO/IEC 9899:1989) не поддерживает ассоциативные массивы, динамические структуры данных произвольной формы и строковые ключи, которые активно используются в вашем PHP‑коде.

В PHP $links — это ассоциативный массив, где ключи — буквы ('a', 'b' и т. д.), а значения — вложенные ассоциативные массивы. В C89 такой структуры «из коробки» нет.

Поэтому «переписать код один в один» невозможно. Вместо этого мы реализуем эквивалентную логику на C89, используя:

    фиксированные индексы для узлов (сопоставим 'a' → 0, 'b' → 1, …, 'f' → 5);

    статическую матрицу смежности для хранения графа;

    структуры для хранения путей и расстояний.

Ниже — полная реализация на C89.

Код C, переписанный ИИ - Алисой (alice.yandex)

#include <stdio.h>
#include <string.h>

/* Максимальное количество узлов (a-f = 6 узлов) */
#define MAX_NODES 6
/* Максимальная длина строки пути (каждый узел - 1 символ + '\0') */
#define MAX_PATH_LEN 32

/* Структура для хранения одного варианта пути до узла */
typedef struct {
    char path[MAX_PATH_LEN];
    int distance;
} WayEntry;

/* Структура для списка путей до конкретного узла */
typedef struct {
    WayEntry entries[MAX_NODES * MAX_NODES]; /* Достаточно большое хранилище */
    int count;
} WaysList;

/* Глобальная структура для хранения всех путей ко всем узлам */
WaysList all_ways[MAX_NODES];

/* Вспомогательная функция для получения индекса по символу ('a' -> 0, 'b' -> 1...) */
int char_to_index(char c) {
    return c - 'a';
}

/* Вспомогательная функция для получения символа по индексу */
char index_to_char(int i) {
    return 'a' + i;
}

int main(void) {
    /*
       Инициализация графа.
       links[i][j] хранит расстояние от узла i до узла j.
       0 означает отсутствие прямого соединения (так как веса > 0).
    */
    int links[MAX_NODES][MAX_NODES] = {0};

    /* Заполнение данными из PHP-массива */
    /* 'a' => array('b' => 3, 'c' => 7, 'd' => 2, 'f' => 119) */
    links[char_to_index('a')][char_to_index('b')] = 3;
    links[char_to_index('a')][char_to_index('c')] = 7;
    links[char_to_index('a')][char_to_index('d')] = 2;
    links[char_to_index('a')][char_to_index('f')] = 119;

    /* 'b' => array('d' => 4, 'e' => 6, 'f' => 8) */
    links[char_to_index('b')][char_to_index('d')] = 4;
    links[char_to_index('b')][char_to_index('e')] = 6;
    links[char_to_index('b')][char_to_index('f')] = 8;

    /* 'c' => array('d' => 5, 'e' => 3, 'f' => 2) */
    links[char_to_index('c')][char_to_index('d')] = 5;
    links[char_to_index('c')][char_to_index('e')] = 3;
    links[char_to_index('c')][char_to_index('f')] = 2;

    /* 'd' => array('e' => 7, 'f' => 4) */
    links[char_to_index('d')][char_to_index('e')] = 7;
    links[char_to_index('d')][char_to_index('f')] = 4;

    /* 'e' => array('f' => 3) */
    links[char_to_index('e')][char_to_index('f')] = 3;

    /* Инициализация структур путей */
    for (int i = 0; i < MAX_NODES; i++) {
        all_ways[i].count = 0;
    }

    char from_char = 'a';
    char to_char = 'f';
    int from = char_to_index(from_char);
    int to = char_to_index(to_char);

    /* Эмуляция: $ways = array($from => array($from => 0)); */
    WaysList *start_ways = &all_ways[from];
    strcpy(start_ways->entries[0].path, &from_char); /* Копируем символ 'a' */
    start_ways->entries[0].distance = 0;
    start_ways->count = 1;

    /* Основной цикл, аналог foreach ($links as $dot => $list) */
    /* Примечание: В оригинальном PHP коде перебор идет по всем узлам графа.
       Логика алгоритма в PHP немного специфична: он расширяет пути последовательно.
       Мы эмулируем эту логику, проходя по узлам в порядке их появления или просто по всем.
       Чтобы точно повторить логику "расширения", нам нужно пройти несколько итераций,
       так как в PHP цикл foreach по статическому массиву $links выполняется один раз,
       но внутри он обновляет $ways, который используется в текущей же итерации для следующих шагов?

       Стоп. Давайте внимательно посмотрим на PHP код:
       foreach ($links as $dot => $list) { ... }
       Внутри цикла мы читаем $ways[$dot]. Если $ways[$dot] еще не создан в предыдущих шагах цикла, он пропускается.
       Так как $links упорядочен как a, b, c, d, e, f, то:
       1. Обрабатываем 'a': у нас есть путь до 'a'. Обновляем пути до b, c, d, f.
       2. Обрабатываем 'b': у нас уже есть пути до 'b' (созданные на шаге 1). Обновляем пути до d, e, f.
       3. Обрабатываем 'c': у нас уже есть пути до 'c'. Обновляем d, e, f.
       ... и так далее.

       Это работает корректно только если порядок ключей в $links совпадает с топологическим порядком графа.
       В данном случае это так. Мы просто пройдемся циклом от 0 до 5.
    */

    for (int dot = 0; dot < MAX_NODES; dot++) {
        /* if (!isset($ways[$dot])) continue; */
        if (all_ways[dot].count == 0) {
            continue;
        }

        /* $curways = $ways[$dot]; */
        WaysList *cur_ways = &all_ways[dot];

        /* foreach ($list as $newdot => $dist) */
        for (int newdot = 0; newdot < MAX_NODES; newdot++) {
            int dist = links[dot][newdot];
            if (dist == 0) {
                continue; /* Нет соединения */
            }

            /* foreach ($curways as $way => $waydist) */
            for (int k = 0; k < cur_ways->count; k++) {
                WayEntry *current_entry = &cur_ways->entries[k];

                /* Вычисляем новый путь и расстояние */
                char new_path[MAX_PATH_LEN];
                strcpy(new_path, current_entry->path);
                new_path[strlen(new_path)] = index_to_char(newdot);
                new_path[strlen(new_path) + 1] = '\0'; /* На всякий случай, хотя strcpy уже поставил \0 после добавления символа? Нет, нужно аккуратно */

                /* Исправление конкатенации: */
                size_t len = strlen(new_path);
                new_path[len] = index_to_char(newdot);
                new_path[len + 1] = '\0';

                int new_dist = current_entry->distance + dist;

                /* Добавляем в список путей для newdot */
                WaysList *target_ways = &all_ways[newdot];
                if (target_ways->count < (MAX_NODES * MAX_NODES)) {
                    strcpy(target_ways->entries[target_ways->count].path, new_path);
                    target_ways->entries[target_ways->count].distance = new_dist;
                    target_ways->count++;
                }
            }
        }
    }

    /* Вывод результатов, аналог print_r($ways) */
    printf("Результаты (аналог print_r):\n");
    for (int i = 0; i < MAX_NODES; i++) {
        char node_name = index_to_char(i);
        if (all_ways[i].count > 0) {
            printf("Пути до узла '%c':\n", node_name);
            for (int j = 0; j < all_ways[i].count; j++) {
                printf("  Путь: %s, Расстояние: %d\n",
                       all_ways[i].entries[j].path,
                       all_ways[i].entries[j].distance);
            }
        } else {
            printf("Пути до узла '%c': не найдено\n", node_name);
        }
    }

    return 0;
}


AnonymUser
() автор топика

Еще немного тестов для сравнения. Вот конвертированный ИИ Алисой код C из моего PHP.

Граф достроил до исходного. Можно сравнить скорость работы:

#include <stdio.h>
#include <string.h>

/* Максимальное количество вершин в пути.
   Граф небольшой, 20 достаточно с запасом. */
#define MAX_PATH 26

/* Функция возвращает указатель на массив соседей для данной вершины.
   Вершины: 'a'..'f'. Возвращает NULL для неверной вершины. */
static const char *get_neighbors(char v) {
    switch (v) {
   case 'a': return "bcdz";
        case 'b': return "defz";
        case 'c': return "defz";
        case 'd': return "efz";
        case 'e': return "fz";
        case 'f': return "ghjz";
        case 'g': return "hijz";
        case 'h': return "ijkz";
        case 'i': return "jklz";
        case 'j': return "kmz";
        case 'k': return "lnoz";
        case 'l': return "mz";
        case 'm': return "noz";
        case 'n': return "oz";
        case 'o': return "pz";
        case 'p': return "qz";
        case 'q': return "rz";
        case 'r': return "sz";
        case 's': return "tuz";
        case 't': return "uvz";
        case 'u': return "vwz";
        case 'v': return "wz";
        case 'w': return "xyz";
        case 'x': return "yz";
        case 'y': return "z";
        case 'z': return "";
        default:  return NULL;
    }
}

/* Вспомогательная функция: найти индекс символа в строке.
   Возвращает -1, если не найден. */
static int str_index_of(const char *s, char c) {
    int i = 0;
    while (s[i] != '\0') {
        if (s[i] == c) return i;
        i++;
    }
    return -1;
}

int main(void) {
	int p =0;
    /* Первый путь (из PHP-скрипта) */
    char path[MAX_PATH];
    int path_len = 0;

    /* Инициализация первого пути: a -> b -> d -> e -> f */
    path[path_len++] = 'a';
    path[path_len++] = 'b';
    path[path_len++] = 'd';
    path[path_len++] = 'e';
    path[path_len++] = 'f';
    path[path_len++] = 'g';
    path[path_len++] = 'h';
    path[path_len++] = 'i';
    path[path_len++] = 'j';
    path[path_len++] = 'k';
    path[path_len++] = 'l';
    path[path_len++] = 'm';
    path[path_len++] = 'n';
    path[path_len++] = 'o';
    path[path_len++] = 'p';
    path[path_len++] = 'q';
    path[path_len++] = 'r';
    path[path_len++] = 's';
    path[path_len++] = 't';
    path[path_len++] = 'u';
    path[path_len++] = 'v';
    path[path_len++] = 'w';
    path[path_len++] = 'x';
    path[path_len++] = 'y';
    path[path_len++] = 'z';

    /* Вывод первого маршрута */
    {
        int i;
        for (i = 0; i < path_len; i++) {
            if (i > 0) printf(", ");
            printf("%c", path[i]);
        }
        printf("\n");
    }
p++;
    int j = path_len - 1;

    while (j > 0) {

        char current_v = path[j - 1];
        const char *neighbors = get_neighbors(current_v);

        /* В PHP: $ar = search_val($x, $j, $arr); */
        /* Здесь neighbors — это аналог $ar */

        int key = str_index_of(neighbors, path[j]);

        /* if (isset($ar[$key + 1])) */
        if ((key != -1) && (neighbors[key + 1] != '\0')) {
            /* $x = array_slice($x, 0, $j); */
            path_len = j;

            /* array_push($x, $ar[$key + 1]); */
            path[path_len++] = neighbors[key + 1];

            /* Достраиваем путь до 'f', всегда беря первого (нулевого) соседа */
            while (1) {

                char last_v = path[path_len - 1];
                if (last_v == 'z') {
                    break;
                }
                const char *next_neighbors = get_neighbors(last_v);
                /* В PHP: search_new_val_for_push_int_x(...)[0] */
                if (next_neighbors[0] != '\0') {
                    path[path_len++] = next_neighbors[0];
                } else {
                    /* Если нет соседей, а мы не в 'f', дальше идти некуда.
                       В логике PHP это не обрабатывается явно, но предотвратим зацикливание. */
                    break;
                }
            }

            j = path_len;

            /* print_r($x); */
            {
                int i;

                for (i = 0; i < path_len; i++) {
                    if (i > 0) printf(", ");
                    printf("%c", path[i]);
                }

                printf("\n");
				p++;


            }
        }

        j--;
    }
 printf("Количество путей: %d",p);
    return 0;
}

У меня с time выдал:

Количество путей: 22061
real	0m1,112s
user	0m0,300s
sys	0m0,377s

Это с выводом всех путей. Результат C.

Средний результат Lua:

real	0m1,550s
user	0m0,409s
sys	0m0,415s

Всё-таки C побыстрее.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от AnonymUser

Вы неправильно меряете, поэтому и результаты такие странные. Я сишку недолюбливаю (за дело), но поиск всех путей в графе с учётом мемоизации у меня состоит из 73-х шагов, запусков рекурсивной функции. Ни в каком мире это не может требовать на С секунды времени.

P.S. Подсказка: уберите хоть печать путей и перепроверьте время.

ugoday ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Чуть-чуть другой алгоритм на lua.

  1. Нет первого ребра, но я так понимаю, - это поправимо.
  2. Последний путь на lua b f j z, а в оригинале: a z

P.S. В алгоритме от firkax тоже последний путь другой: acdefghijklmnopqrstuvwxyz

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от ugoday

Роли особой не играет. Я убрал из C код одно лишнее условие и результат по времени стал таким (после конвертации Алисой есть ещё что оптимизировать):

Количество путей: 22061
real	0m0,494s
user	0m0,108s
sys	0m0,255s
AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от AnonymUser

Роли особой не играет.

С чего вы это взяли? Т.е. вот реально, какие у вас основания так полагать, что вы вообще меряете и на что конкретно ушли эти пол секунды? Это всё ещё в 15 раз медленнее наивного однопоточного кода на схеме, а guile никогда не славился скоростью, если это вам говорит о чём-то.

ugoday ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Седов ни в чём не виноват.

CrX ★★★★★
()
Ответ на: комментарий от ugoday

Чтобы не измерять терминал, достаточно редиректнуть вывод в файл. Мне и в говоу не приходило в stdout это всё выводить, какой толк?

Но если что

$ time php z.php > z.log
real	0m0,241s
user	0m0,076s
sys	0m0,156s
76 на работу и 156 на сисколлы, многовато конечно

Если убрать вывод результата:

$ time php zz.php > z.log

real	0m0,074s
user	0m0,046s
sys	0m0,019s

Если вставить exit в начало (т.е. интерпретатор распарсит файл но выполнять ничего не будет):

 time php zz.php > z.log

real	0m0,041s
user	0m0,022s
sys	0m0,013s

firkax ★★★★★
()
Ответ на: комментарий от ugoday

Ни в каком мире это не может требовать на С секунды времени.

Ты недооцениваешь способности.

Можно из за минуту это посчитать. А если с помощником - то и за час.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Мне и в говоу не приходило в stdout это всё выводить, какой толк?

Так я к тому ж и веду.

ugoday ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Вообще дальше играть в эту игру и нет смысла.

Или писать Си код со структурами (я их плохо знаю).

Или использовать просчитанный заранее первый путь. Мне уже писать на Си такое долго. Поэтому и смотрим предложенное для конвертации н. сетью.

Третий вариант: ждём профи сишника, который понятно, думаю, всех оставит позади.Как тут уже и сказали.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от firkax

Убрал вывод в терминал (из C кода):

Количество путей: 22061
real	0m0,013s
user	0m0,010s
sys	0m0,004s

Убрал вывод на PHP рукописном, да долго:

real	0m3,731s
user	0m3,679s
sys	0m0,051s

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)
Ответ на: комментарий от AnonymUser

ждём профи сишника,

Профи сишник, который действительно профи, воспользуется главным правилом - «если можешь избежать писания на сишке, не пиши на сишке» - особенно, такого рода прикладные вычислительные задачки. Ну в самом деле, питон есть, julia - если прямо вычислительные, всё это на 3 головы красивее, прямее и удобнее пыхосишек. Или вот на современной правильной сишке:

type Node = char;
type Graph = BTreeMap<Node, Vec<Node>>;

// в реальном коде будет fn graph_parser(txt: &str) -> Result<Graph, Err> с анализом ошибок парсенья
fn graph_parser(txt: &str) -> Graph {
   txt.lines().filter(|s| !s.is_empty()).map(|s| {
           let ss: Vec<&str> = s.split('→').collect();
           let nodes: Vec<_> = ss[1].split(',')
               .map(|s| s.trim().chars().next().unwrap()).collect();
           (ss[0].trim().chars().next().unwrap(), nodes)
       }).collect()
}
// самое простое, но может продавить стек
fn number_paths_rec(graph: &Graph, beg: Node, end: Node, mut num: u64) -> u64 {
   if graph[&beg].is_empty() { return num }
   for &node in graph[&beg].iter() {
       if node == end {
           num += 1;
       } else {
           num = number_paths_rec(graph, node, end, num);
       }
   }
   num
}
// это не продавит но расчёт графа в 3-4 раза медленнее
fn number_paths_tail(graph: &Graph, beg: Node, end: Node) -> u64 {
   fn iter(graph: &Graph, end: Node, mut stack: Vec<Node>, mut num: u64) -> u64 {
       match stack.pop() {
           None => num,
           Some(curr_node) => {
               for &node in graph[&curr_node].iter() {
                   if node == end {
                       num += 1;
                   } else {
                       stack.push(node);
                   }
               }
               iter(graph, end, stack, num)
           }
       }
   }
   iter(graph, end, vec![beg], 0)
}

fn main() {
   let graph_txt = "
   a → b, c, d, z
   b → d, e, f, z
   c → d, e, f, z
   d → e, f, z
   e → f, z
   f → g, h, j, z
   g → h, i, j, z
   h → i, j, k, z
   i → j, k, l, z
   j → k, m, z
   k → l, n, o, z
   l → m, z
   m → n, o, z
   n → o, z
   o → p, z
   p → q, z
   q → r, z
   r → s, z
   s → t, u, z
   t → u, v, z
   u → v, w, z
   v → w, z
   w → x, y, z
   x → y, z
   y → z";
   let graph = graph_parser(graph_txt);
   let t0 = Instant::now();
   // let val = number_paths_rec(&graph, 'a', 'z', 0);
   let val = number_paths_tail(&graph, 'a', 'z');
   let t0 = t0.elapsed().as_micros() as f64;
   println!("{} us, {}", t0, val);
}

общее время выполнения порядка 1-2 мс в зависимости от контейнеров и алгоритмов, на рекурисвных алгоритмах можно ещё и хэшмапы поперебирать

zurg ★★
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от zurg

Аааа питонщик все-таки пришел. А я уже думал приз достанется Слону с Алисой пополам. Но я уже строчу рукотворный код на C.

Ждём! Продолжение следует…

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от zurg

И казалось бы, питонщик уходит в отрыв, но тут подоспел мой код:

/*Поиск всех путей на графе. Переписан из кода PHP*/
#include <stdio.h>
#include <string.h>

static int array_search (const char *ar, char el) {
    int i = 0;
    while (ar[i] != '\0') {
        if (ar[i] == el) return i;
        i++;
    }
    return -1;
}

int main() {

int key;
char a[] = "bcdz";
char b[] = "defz";
char c[] = "defz";
char d[] = "efz";
char e[] = "fz";
char f[] = "ghjz";
char g[] = "hijz";
char h[] = "ijkz";
char i[] = "jklz";
char j[] = "kmz";
char k[] = "lnoz";
char l[] = "mz";
char m[] = "noz";
char n[] = "oz";
char o[] = "pz";
char p[] = "qz";
char q[] = "rz";
char r[] = "sz";
char s[] = "tuz";
char t[] = "uvz";
char u[] = "vwz";
char v[] = "wz";
char w[] = "xyz";
char x[] = "yz";
char y[] = "z";
char z[] = "";
char x2[26] = "abdefghijklmnopqrstuvwxyz";
char z2;

int  j2 = strlen(x2)-1;
int last_point = 'z';
int i2 = 0;
char *ar;
int x2_len = 0;
//Печать 1-го
for (i2=0; x2[i2] != '\0'; i2++)
printf("%c", x2[i2]);
printf("\n\r");
int ppp = 1;

while ( j2 != 0 )
 {

    if (x2[j2-1] =='a')
	ar = a;
	if (x2[j2-1] =='b')
	ar = b;
	if (x2[j2-1] =='c')
	ar = c;
	if (x2[j2-1] =='d')
	ar = d;
	if (x2[j2-1] =='e')
	ar = e;
	if (x2[j2-1] =='f')
	ar = f;
	if (x2[j2-1] =='g')
    ar = g;
if (x2[j2-1] =='h')
    ar = h;
if (x2[j2-1] =='i')
    ar = i;
if (x2[j2-1] =='j')
    ar = j;
if (x2[j2-1] =='k')
    ar = k;
if (x2[j2-1] =='l')
    ar = l;
if (x2[j2-1] =='m')
    ar = m;
if (x2[j2-1] =='n')
    ar = n;
if (x2[j2-1] =='o')
    ar = o;
if (x2[j2-1] =='p')
    ar = p;
if (x2[j2-1] =='q')
    ar = q;
if (x2[j2-1] =='r')
    ar = r;
if (x2[j2-1] =='s')
    ar = s;
if (x2[j2-1] =='t')
    ar = t;
if (x2[j2-1] =='u')
    ar = u;
if (x2[j2-1] =='v')
    ar = v;
if (x2[j2-1] =='w')
    ar = w;
if (x2[j2-1] =='x')
    ar = x;
if (x2[j2-1] =='y')
    ar = y;
if (x2[j2-1] =='z')
    ar = z;

  key =  array_search(ar, x2[ j2]);

       if ((key != -1) && (ar[key + 1] != '\0')) {
			//Ставим длину массива равной j
		 x2_len = j2;
		 //Заменим substr
		  x2[j2+1]='\0';

		  //Пишем в массив x
		   x2[x2_len++]= ar[key+1];


    if (x2[strlen(x2)-1] =='a')
	z2 = a[0];
		if (x2[strlen(x2)-1] =='b')
	z2 = b[0];
		if (x2[strlen(x2)-1] =='c')
	z2 = c[0];
	    if (x2[strlen(x2)-1] =='d')
	z2 = d[0];
		if (x2[strlen(x2)-1] =='e')
	z2 = e[0];
		if (x2[strlen(x2)-1] =='f')
	z2 = f[0];
	if (x2[strlen(x2)-1] =='g')
    z2 = g[0];
if (x2[strlen(x2)-1] =='h')
    z2 = h[0];
if (x2[strlen(x2)-1] =='i')
    z2 = i[0];
if (x2[strlen(x2)-1] =='j')
    z2 = j[0];
if (x2[strlen(x2)-1] =='k')
    z2 = k[0];
if (x2[strlen(x2)-1] =='l')
    z2 = l[0];
if (x2[strlen(x2)-1] =='m')
    z2 = m[0];
if (x2[strlen(x2)-1] =='n')
    z2 = n[0];
if (x2[strlen(x2)-1] =='o')
    z2 = o[0];
if (x2[strlen(x2)-1] =='p')
    z2 = p[0];
if (x2[strlen(x2)-1] =='q')
    z2 = q[0];
if (x2[strlen(x2)-1] =='r')
    z2 = r[0];
if (x2[strlen(x2)-1] =='s')
    z2 = s[0];
if (x2[strlen(x2)-1] =='t')
    z2 = t[0];
if (x2[strlen(x2)-1] =='u')
    z2 = u[0];
if (x2[strlen(x2)-1] =='v')
    z2 = v[0];
if (x2[strlen(x2)-1] =='w')
    z2 = w[0];
if (x2[strlen(x2)-1] =='x')
    z2 = x[0];
if (x2[strlen(x2)-1] =='y')
    z2 = y[0];
if (x2[strlen(x2)-1] =='z')
    z2 = z[0];


while(1) {
		//Если дошли до f выходим
		if ((x2[strlen(x2)-1] == last_point)) {
			//Пишем в x2
			 x2[x2_len++] = z2;
			 break;
		 }
			//Пишем в x2
			x2[x2_len++] = z2;
  if (x2[strlen(x2)-1] =='a')
	z2 = a[0];
		if (x2[strlen(x2)-1] =='b')
	z2 = b[0];
		if (x2[strlen(x2)-1] =='c')
	z2 = c[0];
	    if (x2[strlen(x2)-1] =='d')
	z2 = d[0];
		if (x2[strlen(x2)-1] =='e')
	z2 = e[0];
		if (x2[strlen(x2)-1] =='f')
	z2 = f[0];
	if (x2[strlen(x2)-1] =='g')
    z2 = g[0];
if (x2[strlen(x2)-1] =='h')
    z2 = h[0];
if (x2[strlen(x2)-1] =='i')
    z2 = i[0];
if (x2[strlen(x2)-1] =='j')
    z2 = j[0];
if (x2[strlen(x2)-1] =='k')
    z2 = k[0];
if (x2[strlen(x2)-1] =='l')
    z2 = l[0];
if (x2[strlen(x2)-1] =='m')
    z2 = m[0];
if (x2[strlen(x2)-1] =='n')
    z2 = n[0];
if (x2[strlen(x2)-1] =='o')
    z2 = o[0];
if (x2[strlen(x2)-1] =='p')
    z2 = p[0];
if (x2[strlen(x2)-1] =='q')
    z2 = q[0];
if (x2[strlen(x2)-1] =='r')
    z2 = r[0];
if (x2[strlen(x2)-1] =='s')
    z2 = s[0];
if (x2[strlen(x2)-1] =='t')
    z2 = t[0];
if (x2[strlen(x2)-1] =='u')
    z2 = u[0];
if (x2[strlen(x2)-1] =='v')
    z2 = v[0];
if (x2[strlen(x2)-1] =='w')
    z2 = w[0];
if (x2[strlen(x2)-1] =='x')
    z2 = x[0];
if (x2[strlen(x2)-1] =='y')
    z2 = y[0];
if (x2[strlen(x2)-1] =='z')
    z2 = z[0];

				}
				//Переменную ставим равной массиву
				 j2=strlen(x2);
				//Выводим
				printf("%s", x2);
				printf("\n\r");
				ppp++;
			}
 j2--;
		}
		printf("%d", ppp);
 }



Время с выводом:

real	0m0,544s
user	0m0,169s
sys	0m0,285s

Время без вывода:

real	0m0,097s
user	0m0,093s
sys	0m0,005s

И … сертификат на МакБук Про достается всё-таки мне. =) Неожиданный поворт в нашем шоу. Все-таки люди победили нейронные сети.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)
Ответ на: комментарий от AnonymUser

Что-то после работы долго ломал голову, как сделать что-то вроде substr на C89, только, чтобы попроще. Потом вдруг осенило:

 x2[j2+1]='\0';

Иногда, и правда, всё проще, чем кажется…

AnonymUser
() автор топика
Ответ на: комментарий от ugoday

Сократил:

/*Поиск всех путей на однонаправленном графе. Переписан из кода PHP на язык C стандарта 89*/
#include <stdio.h>
#include <string.h>
/*Объявим граф глобально*/
char a[] = "bcdz";
char b[] = "defz";
char c[] = "defz";
char d[] = "efz";
char e[] = "fz";
char f[] = "ghjz";
char g[] = "hijz";
char h[] = "ijkz";
char i[] = "jklz";
char j[] = "kmz";
char k[] = "lnoz";
char l[] = "mz";
char m[] = "noz";
char n[] = "oz";
char o[] = "pz";
char p[] = "qz";
char q[] = "rz";
char r[] = "sz";
char s[] = "tuz";
char t[] = "uvz";
char u[] = "vwz";
char v[] = "wz";
char w[] = "xyz";
char x[] = "yz";
char y[] = "z";
char z[] = "";
/*Вернёт элемент, который потом допишем в массив x*/
char element_search_to_push ( char *first_way) {

char elem_to_push;
  if (first_way[strlen(first_way)-1] =='a')
	elem_to_push = a[0];
		if (first_way[strlen(first_way)-1] =='b')
	elem_to_push = b[0];
		if (first_way[strlen(first_way)-1] =='c')
	elem_to_push = c[0];
	    if (first_way[strlen(first_way)-1] =='d')
	elem_to_push = d[0];
		if (first_way[strlen(first_way)-1] =='e')
	elem_to_push = e[0];
		if (first_way[strlen(first_way)-1] =='f')
	elem_to_push = f[0];
	if (first_way[strlen(first_way)-1] =='g')
    elem_to_push = g[0];
if (first_way[strlen(first_way)-1] =='h')
    elem_to_push = h[0];
if (first_way[strlen(first_way)-1] =='i')
    elem_to_push = i[0];
if (first_way[strlen(first_way)-1] =='j')
    elem_to_push = j[0];
if (first_way[strlen(first_way)-1] =='k')
    elem_to_push = k[0];
if (first_way[strlen(first_way)-1] =='l')
    elem_to_push = l[0];
if (first_way[strlen(first_way)-1] =='m')
    elem_to_push = m[0];
if (first_way[strlen(first_way)-1] =='n')
    elem_to_push = n[0];
if (first_way[strlen(first_way)-1] =='o')
    elem_to_push = o[0];
if (first_way[strlen(first_way)-1] =='p')
    elem_to_push = p[0];
if (first_way[strlen(first_way)-1] =='q')
    elem_to_push = q[0];
if (first_way[strlen(first_way)-1] =='r')
    elem_to_push = r[0];
if (first_way[strlen(first_way)-1] =='s')
    elem_to_push = s[0];
if (first_way[strlen(first_way)-1] =='t')
    elem_to_push = t[0];
if (first_way[strlen(first_way)-1] =='u')
    elem_to_push = u[0];
if (first_way[strlen(first_way)-1] =='v')
    elem_to_push = v[0];
if (first_way[strlen(first_way)-1] =='w')
    elem_to_push = w[0];
if (first_way[strlen(first_way)-1] =='x')
    elem_to_push = x[0];
if (first_way[strlen(first_way)-1] =='y')
    elem_to_push = y[0];
if (first_way[strlen(first_way)-1] =='z')
    elem_to_push = z[0];

	return elem_to_push;
}
/*Возвращает указатель на первый путь x*/
char *element_search ( char *first_way,  int j2 ) {

char *ar;
 if (first_way[j2-1] =='a')
	ar = a;
	if (first_way[j2-1] =='b')
	ar = b;
	if (first_way[j2-1] =='c')
	ar = c;
	if (first_way[j2-1] =='d')
	ar = d;
	if (first_way[j2-1] =='e')
	ar = e;
	if (first_way[j2-1] =='f')
	ar = f;
	if (first_way[j2-1] =='g')
    ar = g;
if (first_way[j2-1] =='h')
    ar = h;
if (first_way[j2-1] =='i')
    ar = i;
if (first_way[j2-1] =='j')
    ar = j;
if (first_way[j2-1] =='k')
    ar = k;
if (first_way[j2-1] =='l')
    ar = l;
if (first_way[j2-1] =='m')
    ar = m;
if (first_way[j2-1] =='n')
    ar = n;
if (first_way[j2-1] =='o')
    ar = o;
if (first_way[j2-1] =='p')
    ar = p;
if (first_way[j2-1] =='q')
    ar = q;
if (first_way[j2-1] =='r')
    ar = r;
if (first_way[j2-1] =='s')
    ar = s;
if (first_way[j2-1] =='t')
    ar = t;
if (first_way[j2-1] =='u')
    ar = u;
if (first_way[j2-1] =='v')
    ar = v;
if (first_way[j2-1] =='w')
    ar = w;
if (first_way[j2-1] =='x')
    ar = x;
if (first_way[j2-1] =='y')
    ar = y;
if (first_way[j2-1] =='z')
    ar = z;
	return ar;
}

static int array_search (const char *ar, char el) {
    int i = 0;
    while (ar[i] != '\0') {
        if (ar[i] == el) return i;
        i++;
    }
    return -1;
}

int main(void) {
int key;
/*Первый путь*/
char first_way[26] = "abdefghijklmnopqrstuvwxyz";
char elem_to_push;

int  j2 = strlen(first_way)-1;
int last_point = 'z';
int i2 = 0;
char *ar;
int first_way_len = 0;

/*Печать 1-го*/
for (i2=0; first_way[i2] != '\0'; i2++)
printf("%c", first_way[i2]);
printf("\n\r");
int all_ways_count = 1;


while ( j2 != 0 )
 {
    /*Поиск элемента*/
	ar=element_search (first_way,  j2 );
	/*Поиск ключа*/
   key =  array_search(ar, first_way[ j2]);
       if ((key != -1) && (ar[key + 1] != '\0')) {
			/*Ставим длину массива равной j2*/
		 first_way_len = j2;
		 /*Заменим substr*/
		  first_way[j2+1]='\0';
		  /*Пишем в массив x*/
		   first_way[first_way_len++]= ar[key+1];
			elem_to_push=element_search_to_push(first_way);
while(1) {
		/*Если дошли до f выходим*/
		if ((first_way[strlen(first_way)-1] == last_point)) {
			/*Пишем в first_way*/
			 first_way[first_way_len++] = elem_to_push;
			 break;
		 }
			/*Пишем в first_way*/
			first_way[first_way_len++] = elem_to_push;
		elem_to_push=element_search_to_push(first_way);
				}
				/*Переменную ставим равной массиву*/
				 j2=strlen(first_way);
				/*Выводим*/
				printf("%s", first_way);
				printf("\n\r");
				all_ways_count++;
			}
 j2--;
		}
		printf("%d", all_ways_count);
 }



AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от AnonymUser

Что вы будете делать, если размер графа несколько увеличится? Вот, например: https://pastebin.com/NrZcM8BS (тут в лимит pastebin’а не уложился, поэтому пришлось сделать так: 1. оригинальный файл был в формате dot; 2. этот файл был пожат bzip2; 3. бинарник был закодирован base64, так что для распаковки нужно проделать обратную трансформацию).

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Конечно, реализацию придется менять в таком случае. Важно, что можно, вероятно, считать алгоритм корректным (условно) для любых n.

P.S. Никто же не собирается мою реализацию использовать на практике?! Если требуется использовать в каком-то проекте, то тут, конечно, требуется основательный подход.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Для статистики: в графе выше (каждый следующий узел связан со всеми предыдущими) для узла №999 нашлось 2678771517965668302371062622650004526403512029263834018609375970925877627812340306232995947039239645318986682293882867062967863214230785108996144393674643700983641943706057746355268651265592785469488545538261618745895485316849691889791385986519265728642799119421635541915107457913156096709301417017344 путей из узла №0. И это заняло всего лишь

Evaluation took:
  0.062 seconds of real time
  0.062159 seconds of total run time (0.048126 user, 0.014033 system)

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

ugoday ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)