CodeGolf: Найдите уникальные пути
-
13-10-2019 - |
Вопрос
Вот довольно простая идея, в этом Pastebin Я опубликовал несколько номеров. Они представляют узлы направленного графика. Вход в stdin
Будет из формы (они будут числа, я буду использовать пример здесь)
c d
q r
a b
b c
d e
p q
так x y
означает x
подключен к y
(нет наоборот)
В этом примере есть 2 пути. a->b->c->d->e
а также p->q->r
.
Вам нужно распечатать все уникальные пути с этого графика, вывод должен быть форматом
a->b->c->d->e
p->q->r
Заметки
- Вы можете предположить, что числа выбираются так, что один путь не пересекает другой (один узел принадлежит одному пути)
- Пары в случайном порядке.
- Это более 1 пути, они могут быть разные длины.
- Все цифры менее 1000.
Если вам нужна более подробная информация, пожалуйста, оставьте комментарий. Я внеслю в изменения по мере необходимости.
Бесстыдный
Для тех, кто любит CodeGolf, пожалуйста, совершите Область51 Для своего собственного сайта :) (для тех, кому не нравится, пожалуйста, поддержите его, так что мы будем держаться подальше ...)
Решение
Рубин - 132 125 87
h=Hash[a=[*$<].map(&:split)]
1000.times{a.map!{|i|i+[h[i[-1]]]-[nil]}}
puts a.sort_by{|i|-i.size}.uniq(&:last).map{|i|i*'->'}
Взял идею Nas Banov о h.keys-h.values
:
h=Hash[[*$<].map &:split]
puts (h.keys-h.values).map{|i|s=i
s+='->'+i=h[i]while h[i];s}
Другие советы
C89 - 212 204 символа
#define M 1001
int t[M],r[M],a,b;main(){while(scanf("%d%d",&a,&b)>0)t[a+1]=r[a+1]=b+1;
for(a=1;a<M;a++)r[t[a]]=0;for(a=1;a<M;a++)if(r[a]){printf("%d",a-1);
for(b=t[a];b;b=t[b])printf("->%d",b-1);puts("");}}
Ненужные новшество не учитываются.
Команда:
$ wget -O - http://pastebin.com/download.php?i=R2PDGb2w | ./unique-paths
Выход:
477->4->470->350->401->195->258->942->263->90->716->514->110->859->976->104->119->592->968->833->731->489->364->847->727
784->955->381->231->76->644->380->861->522->775->565->773->188->531->219->755->247->92->723->726->606
821->238->745->504->99->368->412->142->921->468->315->193->674->793->673->405->185->257->21->212->783->481->269
Красивая версия:
#include <stdio.h>
int main(void)
{
/* Note: {0} initializes all items to zero. */
int target[1001] = {0}; /* If a → b, then target[a+1] == b+1. */
int root[1001] = {0}; /* If a is a root, then root[a+1] != 0. */
int a, b, i, next;
/* Read input numbers, setting the target of each node.
Also, mark each source node as a root. */
while (scanf("%d %d", &a, &b) == 2)
target[a+1] = root[a+1] = b+1;
/* Mark each node that is pointed to as not a root. */
for (i = 1; i <= 1000; i++)
root[target[i]] = 0;
/* For each root node, print its chain. */
for (i = 1; i <= 1000; i++) {
if (root[i] != 0) {
printf("%d", i-1);
for (next = target[i]; next != 0; next = target[next])
printf("->%d", next-1);
printf("\n");
}
}
return 0;
}
Хотя это и не ответ, следующий сценарий Linux рисует график входного файла:
cat FILE | (echo "digraph G {"; awk '{print "\t" $1 "-> " $2;}'; echo "}") \
| dot -Tpng > out.png && eog out.png
Вам понадобиться График установлен для dot
команда и eog
является ГНОМСтроитель изображений.
Запустите на входном файле, график выглядит следующим образом:
Повернулся на 90 ° и уменьшился (Смотрите оригинал)
Как вы можете видеть, входной график представляет собой просто коллекцию отдельных списков без общих узлов и без циклов.
Питон
120 символов
Мне нравится, насколько легко это читается в Python:
import sys
d=dict(map(str.split,sys.stdin))
for e in set(d)-set(d.values()):
while e in d:print e,'->',;e=d[e]
print e
И результат пробега через образец паста-бин:
784 -> 955 -> 381 -> 231 -> 76 -> 644 -> 380 -> 861 -> 522 -> 775 -> 565 -> 773 -> 188 -> 531 -> 219 -> 755 -> 247 -> 92 -> 723 -> 726 -> 606
821 -> 238 -> 745 -> 504 -> 99 -> 368 -> 412 -> 142 -> 921 -> 468 -> 315 -> 193 -> 674 -> 793 -> 673 -> 405 -> 185 -> 257 -> 21 -> 212 -> 783 -> 481 -> 269
477 -> 4 -> 470 -> 350 -> 401 -> 195 -> 258 -> 942 -> 263 -> 90 -> 716 -> 514 -> 110 -> 859 -> 976 -> 104 -> 119 -> 592 -> 968 -> 833 -> 731 -> 489 -> 364 -> 847 -> 727
Луа, 166 байтов
Да, конечно, кодовый, где Луа не отстой. Дополнительные симпатии: работает над всем, что разделено пространство (числа любого размера, строк, ...)
Не гольф-версия:
-- Read in a file from stdout filled with pairs of numbers representing nodes of a (single-)directed graph.
-- x y means x->y (but not y->x)
g={}t={}w=io.write
i=io.read"*a" -- read in numbers from stdin
for x,y in i:gmatch"(%w+) (%w+)" do -- parse pairs
t[y]=1 -- add y to destinations (which never can be a starting point)
g[x]=y
end
for k,v in pairs(g) do -- go through all links
if not t[k] then -- only start on starting points
w(k) -- write the startingpoint
while v do -- as long as there is a destination ...
w('->',v) -- write link
v=g[v] -- next destination
end
w'\n'
end
end
Версия с гольфом:
g={}t={}w=io.write for x,y in io.read"*a":gmatch"(%w+) (%w+)"do t[y]=1 g[x]=y end for k,v in pairs(g)do if not t[k]then w(k)while v do w('->',v)v=g[v]end w'\n'end end
Хаскелл - 174 142 137 133 персонажа
import List
a#m=maybe[](\x->"->"++x++x#m)$lookup a m
q[f,s]=f\\s>>=(\a->a++a#zip f s++"\n")
main=interact$q.transpose.map words.lines
Оснащенное:
import Data.List
type Node = String
follow :: Node -> [(Node,Node)] -> String
follow node pairs = maybe "" step $ lookup node pairs
where step next = "->" ++ next ++ follow next pairs
chains :: [[Node]] -> String
chains [firsts,seconds] = concatMap chain $ firsts \\ seconds
where chain node = node ++ follow node pairs ++ "\n"
pairs = zip firsts seconds
process :: [String] -> String
process = chains . transpose . map words
main :: IO ()
main=interact $ process . lines
Менее элегантный подход, чем раньше, но короче! Вдохновлен идеей Нэс Банова о h.keys-h.values
PHP - 155
foreach(file($argv[1])as$x){$x=explode(' ',$x);$g[$x[0]+0]=$x[1]+0;}
foreach($g as$a=>$b)if(!in_array($a,$g)){echo$a;while($b=$g[$b])echo"->$b";echo"\n";}
Весь файл выглядит так:
<?php
error_reporting(0);
foreach(file($argv[1])as$x){$x=explode(' ',$x);$g[$x[0]+0]=$x[1]+0;}
foreach($g as$a=>$b)if(!in_array($a,$g)){echo$a;while($b=$g[$b])echo"->$b";echo"\n";}
Бежать:
$ php graph.php graph.txt
Красивая версия:
$lines = file($argv[1]);
foreach ($lines as $line) {
$vertexes = explode(' ',$line);
$graph[$vertexes[0]+0] = $vertexes[1]+0; // the +0 forces it to an integer
}
foreach ($graph as $a => $b) {
//searches the vertexes that are pointed to for $a
if (!in_array($a,$graph)) {
echo $a;
for ($next = $b; isset($graph[$next]); $next = $graph[$next]) {
echo "->$next";
}
//because the loop doesn't run one last time, like in the golfed version
echo "->$next\n";
}
}
Ocaml
402 символа
По сути, адаптация версии Haskell, длина которой поражает меня. Конечно, есть способ добиться большего Str
и/или Пересмотренный синтаксис.
open List;;open String;; let q(a,b,p)=print_string(p^b^"\n")in let rec f(a,b,p)=function []->[a,b,p]|(x,y,q)::l when x=b->f(a,y,p^q)l|(x,y,q)::l when y=a->f(x,b,q^p)l|h::t->h::(f(a,b,p)t)in let t s=let i=index s ' 'in let h=sub s 0 i in h,sub s (i+1) ((length s) -i-1),h^"->"in let s=ref []in try while true do let l=read_line ()in s:=l::!s done with End_of_file->List.iter q(fold_right f(map t !s)[])
Оснащенное:
open List;;
open String;;
let print (a,b,p) = print_string (p^b^"\n") in
let rec compose (a,b,p) = function
[] -> [a,b,p]
|(x,y,q)::l when x=b->compose (a,y,p^q) l
|(x,y,q)::l when y=a->compose (x,b,q^p) l
|h::t->h::(compose(a,b,p) t) in
let tokenize s = let i = index s ' ' in
let h = sub s 0 i in
h,sub s (i+1) ((length s) -i-1),h^"->" in
let lines = ref [] in
try
while true do
let l = read_line () in
lines := l::!lines
done
with
End_of_file-> List.iter print (fold_right compose (map tokenize !lines) [])
Ява
372 337 304 байта
Обновлять :
- Удаленные дженерики. И, видимо, класс может сделать, не будучи «публичным» (Thnx Sean)
- Удаленный класс, заменен Enum. (См. Комментарии, Thnx nabb)
import java.util.*;enum M{M;{Scanner s=new Scanner(System.in);final Map g=new HashMap();while(s.hasNext()){g.put(s.nextInt(),s.nextInt());}for(int a:new HashSet<Integer>(g.keySet()){{removeAll(g.values());}}){while(g.containsKey(a)){System.out.print(a+"->");a=(Integer)g.get(a);}System.out.println(a);}}}