CodeGolf: поиск уникальных путей
Вот довольно простая идея, в этом pastebin я разместил несколько пар чисел. Они представляют собой узлы направленного графа. Входные данные в stdin
будут иметь вид, (они будут числами, я буду использовать пример здесь)
c d
q r
a b
b c
d e
p q
Так что x y
означает, что x
связано с y
(not viceversa)
В этом примере есть 2 пути. a->b->c->d->e
и p->q->r
.
Вам нужно вывести все уникальные пути из этого графика Выход должен быть следующим: формат
a->b->c->d->e
p->q->r
Примечания
-
Можно предположить, что числа подобраны таким образом, что один путь не пересекается с другим (один узел принадлежит одному пути)
Пары расположены в случайном порядке.
Это более 1 пути, они могут быть разной длины.
- Все числа меньше 1000.
Если вам нужна дополнительная информация, пожалуйста, оставьте комментарий. Я внесу необходимые поправки.
Бесстыдник-Вилка
Для те, кто любит Codegolf, пожалуйста, совершите на Area51 для своего собственного сайта:) (для тех, кто не любит его, Пожалуйста, поддержите его, так что мы будем держаться подальше от вашего пути...)
9 ответов:
Рубин -
132 12587
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*'->'}
Взял идею НАСА Банова о
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 -
212204 символы#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
Вам понадобится Graphviz, установленный для команды
dot
, аeog
- это средство просмотра изображений GNOME.Запускаем на входном файле, график выглядит так:
повернутый на 90° и уменьшенный масштаб (см. оригинал)
Как вы можете видеть, входной граф - это просто набор односвязных списков без общих узлов и никаких циклов.
Python
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
Lua, 166 байт
Ой да, наконец-то codegolf, где Lua не сосет. Extra goodie: работает со всем, что разделено пробелом (числа любого размера, строки, ...)
Версия без гольфа:
-- 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
Хаскелл -
174142137133 символы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
Ungolfed:
Менее элегантный подход, чем раньше, но короче! Вдохновленный идеей Н. С. Банова о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 символа
В основном адаптация версии Хаскелла, длина которой поражает меня. Конечно, есть способ сделать лучше с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)[])
Ungolfed:
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) [])
Java
372 337304 байтыОбновление :
- Удаленные Дженерики. И, по-видимому, класс может обойтись без того, чтобы быть " публичным` (Thnx Sean)
- удален класс, заменен перечислением. (См. Комментарии, 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);}}}