Игра Названия городов

16

Если хотите, напишите программу, которая сортирует города по правилам игры с названиями городов.

  • Каждое название города должно начинаться с последней буквы в названии предыдущего города. НапримерLviv -> v -> Viden -> n -> Neapolis -> s -> Sidney -> y -> Yokogama -> a -> Amsterdam -> m -> Madrid -> d -> Denwer

  • В отсортированном списке первая буква первого города и последняя буква последнего не должны совпадать, ничто не должно совпадать.

  • Вы можете предположить, что названия городов имеют только буквы.
  • Вывод программы должен иметь такую ​​же прописную букву, как ввод

Пример:

% ./script Neapolis Yokogama Sidney Amsterdam Madrid Lviv Viden Denwer
["Lviv", "Viden", "Neapolis", "Sidney", "Yokogama", "Amsterdam", "Madrid", "Denwer"]
defhlt
источник
2
Можем ли мы предположить, что всегда найдется правильное решение?
Гарет
@ Гарет, да, вы можете
defhlt
второе правило - «[...] не должно совпадать с чем-либо» - это требование или просто утверждение о том, что допустимо несоответствие между первой и последней буквой? (например: список ["Viden" ... "Lviv"]недействителен?)
Кристиан Лупаску
@ w0lf под словом «не должен», я имел в виду, что это не обязательно, это не обязательно. Так что твой пример верен.
defhlt
Подсказка: если вам нужно хорошее решение, вы можете свести это к вычислению эйлеровых путей, где каждая буква является вершиной, а каждое слово - ребром. (Например, Берлин - это ребро BN ). Это разрешимо в O (n), где n - количество ребер.
FUZxxl

Ответы:

11

Рубин, 58 55 44 персонажа

p$*.permutation.find{|i|i*?,!~/(.),(?!\1)/i}

Еще одна рубиновая реализация. Также используется регулярное выражение без учета регистра (как старое решение Ventero ), но тест проводится по-другому.

Предыдущая версия:

p$*.permutation.find{|i|(i*?,).gsub(/(.),\1/i,"")!~/,/}
Говард
источник
Очень хорошо! И я думаю, что вы можете уменьшить это значение до 55, если будете использовать !~вместо отрицания всего выражения.
Кристиан Лупаску
Это умное регулярное выражение
defhlt
@ w0lf Конечно! Как я мог не думать об этом?
Говард
5

Питон ( 162 141 124)

Грубая сила для победы.

from itertools import*
print[j for j in permutations(raw_input().split())if all(x[-1]==y[0].lower()for x,y in zip(j,j[1:]))]
beary605
источник
1
Я думаю, что вы можете удалить &(j[0][0]!=j[-1][-1])условие; см. вопрос к комментариям выше.
Кристиан Лупаску
1
124 from itertools import*;print[j for j in permutations(raw_input().split())if all(x[-1]==y[0].lower()for x,y in zip(j,j[1:]))]
Ev_genus
Я пытаюсь обернуть голову вокруг того, что происходит в этой функции. Что именно j, x, y? Как они определены? Извините, если эти вопросы неэффективны, я новичок в Python и хотел бы поработать с ним еще.
Роб
@MikeDtrick: jсодержит перестановку городов, которая генерируется с помощью permutationsкоманды. Большое значение ifв конце подтверждает, что для всех значений в j, последняя буква одного значения в jсовпадает с первой буквой следующего значения в j. Честно говоря, я тоже не знаю, что zipделает, zipработает таинственным образом.
beary605
Хорошо, спасибо за объяснение! +1
Роб
5

Рубин 1.9, 63 54 персонажа

Новое решение основано на Говарда «S решения :

p$*.permutation.max_by{|i|(i*?,).scan(/(.),\1/i).size}

При этом используется тот факт, что всегда будет действительное решение.

Старое решение, основанное на w0lf «s решения :

p$*.permutation.find{|i|i.inject{|a,e|a&&e[0]=~/#{a[-1]}/i&&e}}
Ventero
источник
Хорошая идея с max_by. И ваша новая версия вдохновила меня на еще более новую (и более короткую) версию.
Говард
@ Говард Спасибо! Ваше новое решение действительно потрясающее, его будет сложно победить. ;)
Вентеро
4

Рубин 74 72 104 103 71 70

p$*.permutation.find{|i|i.inject{|a,e|a[-1].casecmp(e[0])==0?e:?,}>?,}

Демо: http://ideone.com/MDK5c (в демо, которое я использовал gets().split()вместо $*; я не знаю, может ли Ideone имитировать аргументы командной строки).

Кристиан Лупаску
источник
выглядит похоже на мой вариант, $*.permutation{|p|p p if p.inject(p[0][0]){|m,e|m.casecmp(e[0])==0?e[-1]:?_}>?_}но ваш на 9 символов короче!
defhlt
2
p$*.permutation.find{|i|i.inject{|a,e|a&&e[0]=~/#{a[-1]}/i&&e}}немного короче. Решение Ruby 1.8 (!), p$*.permutation.find{|i|i.inject{|a,e|a&&a[-1]-32==e[0]&&e}}
Которое
@Ventero Использование регулярных выражений без учета регистра - блестящая идея! Пожалуйста, отправьте это как ваш собственный ответ; Я не достоин использовать это. :)
Кристиан Лупаску
@Ventero -32решение также очень гениальное, но оно основано на том факте, что имена начинаются с заглавной буквы и заканчиваются строчными, что не всегда так.
Кристиан Лупаску
@ w0lf Вы правы, я думал, что прочитал в спецификации, что это будет так, но, очевидно, я ошибаюсь. ;)
Вентеро
3

Python, 113

Очень похоже на ответ @ beary605, и даже более грубо.

from random import*
l=raw_input().split()
while any(x[-1]!=y[0].lower()for x,y in zip(l,l[1:])):
 shuffle(l)
print l
Нолен Роял
источник
1
Woohoo, стиль сортировки Bogo!
beary605
3

Хаскелл , 94 74 байта

g[a]=[[a]]
g c=[b:r|b<-c,r<-g[x|x<-c,x/=b],last b==[r!!0!!0..]!!32]
head.g

Рекурсивно находит все решения. -7 байт, если можно вывести все решения вместо первого. Спасибо @Lynn за избавление от надоедливого импорта, сократив 18 байт за счет!

Попробуйте онлайн!

Angs
источник
Вы можете избавиться от Data.Charимпорта с помощью last b==[r!!0!!0..]!!32. Кроме того, вам не нужны парены вg[x|x<-c,x/=b]
Линн
1
@ Линн приятно, я как-то подумала, fromEnumчто это обязательно. Забавно, я уже убрал эти скобки, но, должно быть, скопировал их не с той вкладки ...
Angs
2

GolfScript, 78 символов

" ":s/.{1${1$=!},{:h.,{1$-1={1$0=^31&!{[1$1$]s*[\](\h\-c}*;}+/}{;.p}if}:c~;}/;

Первая версия в GolfScript. Это также делает подход грубой силы. Вы можете увидеть скрипт, запущенный на примере ввода онлайн .

Говард
источник
2

Шелуха , 10 байт

←fΛ~=o_←→P

Попробуйте онлайн!

объяснение

←fΛ~=(_←)→P  -- example input: ["Xbc","Abc","Cba"]
          P  -- all permutations: [["Xbc","Abc","Cba"],…,[Xbc","Cba","Abc"]]
 f           -- filter by the following (example with ["Xbc","Cba","Abc"])
  Λ          -- | all adjacent pairs ([("Xbc","Cba"),("Cba","Abc")])
   ~=        -- | | are they equal when..
     (_←)    -- | | .. taking the first character lower-cased
         →   -- | | .. taking the last character
             -- | : ['c'=='c','a'=='a'] -> 4
             -- : [["Xbc","Cba","Abc"]]
←            -- take the first element: ["Xbc","Cba","Abc"]

В качестве альтернативы 10 байтов

Мы также можем посчитать количество соседних пар, которые удовлетворяют предикату ( #), отсортировать по ( Ö) и взять последний элемент ( ) для того же количества байтов:

→Ö#~=o_←→P

Попробуйте онлайн!

ბიმო
источник
2

Желе , 25 18 байт (Улучшения приветствуются!)

UżḢŒuE
ḲŒ!çƝẠ$ÐfḢK

Попробуйте онлайн!

UżḢŒuE        dyadic (2-arg) "check two adjacent city names" function:
Uż            pair (żip) the letters of the reversed left argument with the right argument,
  Ḣ           get the Ḣead of that pairing to yield just the last letter of left and the first letter of right,
   Œu         capitalize both letters,
     E       and check that they're equal!
ḲŒ!çƝẠ$ÐfḢK    i/o and check / fold function:
ḲŒ!            split the input on spaces and get all permutations of it,
   çƝẠ$        run the above function on every adjacent pair (çƝ), and return true if Ȧll pairs are true
       Ðf      filter the permutations to only get the correct ones,
         ḢK    take the first of those, and join by spaces!

Спасибо @Lynn за большинство этих улучшений!

25-байтовое решение:

Uḣ1Œu=⁹ḣ1
çƝȦ
ḲŒ!©Ç€i1ị®K

Попробуйте онлайн!

Uḣ1Œu=⁹ḣ1      dyadic (2-arg) "check two adjacent city names" function:
Uḣ1Œu          reverse the left arg, get the ḣead, and capitalize it (AKA capitalize the last letter),
     =⁹ḣ1      and check if it's equal to the head (first letter) of the right argument.
çƝȦ            run the above function on every adjacent pair (çƝ), and return true if Ȧll pairs are true
ḲŒ!©Ç€i1ị®K     main i/o function:
ḲŒ!©           split the input on spaces and get all its permutations, ©opy that to the register
    Ç€         run the above link on €ach permutation,
      i1       find the index of the first "successful" permutation,
        ị®K    and ®ecall the permutation list to get the actual ordering at that ịndex, separating output by spaces
Гарри
источник
2
Некоторые улучшения: попробуйте онлайн! Я написал небольшой список изменений в поле «Вход». (О, после того, как Ðfя использую, Xчтобы выбрать случайное решение вместо первого, но работает так же хорошо.)
Линн
@ Линн Спасибо большое! Часть zip была очень умной, и я думаю, что могу использовать это Ðfбыстро во многих других моих программах, чтобы сэкономить место!
Гарри
1

Mathematica 236 символов

Определите список городов:

d = {"Neapolis", "Yokogama", "Sidney", "Amsterdam", "Madrid", "Lviv", "Viden", "Denver"}

Найдите путь, который включает в себя все города:

c = Characters; f = Flatten;
w = Outer[List, d, d]~f~1;
p = Graph[Cases[w, {x_, y_} /;x != y \[And] (ToUpperCase@c[x][[-1]]== c[y][[1]]) :> (x->y)]];
v = f[Cases[{#[[1]], #[[2]], GraphDistance[p, #[[1]], #[[2]]]} & /@  w, {_, _, Length[d] - 1}]];
FindShortestPath[p, v[[1]], v[[2]]]

Выход:

{"Lviv", "Viden", "Neapolis", "Sidney", "Yokogama", "Amsterdam","Madrid", "Denver"}

Вышеупомянутый подход предполагает, что города могут быть организованы в виде графика пути.


График p показан ниже:

график

DavidC
источник
1

С 225

#define S t=v[c];v[c]=v[i];v[i]=t
#define L(x)for(i=x;i<n;i++)
char*t;f;n=0;main(int c,char**v){int i;if(!n)n=c,c=1;if(c==n-1){f=1;L(2){for(t=v[i-1];t[1];t++);if(v[i][0]+32-*t)f=n;}L(f)puts(v[i]);}else L(c){S;main(c+1,v);S;}}

Запускать с именами стран в качестве аргументов командной строки

Замечания:

  • грубая сила генерации перестановок
  • для проверки предполагается, что названия стран начинаются с заглавных букв и заканчиваются строчными.
  • предполагает, что есть только один ответ
  • В C предполагается, что массив ** v в main () доступен для записи
ребенок кролика
источник
Не уверен, что это точно, но если вы делаете #define L(x)for(int i=x;i<n;i++)и не объявляете iв начале main, сохраните 1 байт.
Цатоггуа,
1

J, 69 65 60 59 54 символов

Несколько не в темпе.

{.l\:+/2=/\|:tolower;"2({.,{:)@>l=.(i.@!@#A.]);:1!:1[1

Пример:

   {.l\:+/2=/\|:tolower;"2({.,{:)@>l=.(i.@!@#A.]);:1!:1[1
Neapolis Yokogama Sydney Amsterdam Madrid Lviv Viden Denwer
+----+-----+--------+------+--------+---------+------+------+
|Lviv|Viden|Neapolis|Sydney|Yokogama|Amsterdam|Madrid|Denwer|
+----+-----+--------+------+--------+---------+------+------+
Gareth
источник
1

C #, 398

А вот C # с Linq 5 центов

IEnumerable<string>CityNameGame(string[]input){var cities=new List<string>(input);string lastCity=null;while(cities.Any()){var city=lastCity??cities.First();lastCity=cities.First(name=>string.Equals(city.Substring(city.Length-1),name.Substring(0,1),StringComparison.CurrentCultureIgnoreCase));cities.RemoveAll(name=>name==city||name==lastCity);yield return string.Format("{0}→{1}",city,lastCity);}}
Аким
источник
0

К, 96

{m@&{&/(~).'+(,_1_1#'x),,-1_-1#'x}@'$m:{$[x=1;y;,/.z.s[x-1;y]{x,/:{x@&~x in y}[y;x]}\:y]}[#x;x]}

,

k){m@&{&/(~).'+(,_1_1#'x),,-1_-1#'x}@'$m:{$[x=1;y;,/.z.s[x-1;y]{x,/:{x@&~x in y}[y;x]}\:y]}[#x;x]}`Neapolis`Yokogama`Sidney`Amsterdam`Madrid`Lviv`Viden`Denver
Lviv Viden Neapolis Sidney Yokogama Amsterdam Madrid Denver
tmartin
источник
0

C # (.NET Core) , 297 байт

using System;
using System.Linq;
var S="";int I=0,C=s.Count();for(;I<C;I++)S=Array.Find(s,x=>s[I].Substring(0,1).ToUpper()==x.Substring(x.Length-1).ToUpper())==null?s[I]:S;for(I=0;I<C;I++){Console.Write(S+" ");S=C>I?Array.Find(s,x=>S.Substring(S.Length-1).ToUpper()==x.Substring(0,1).ToUpper()):"";}

Попробуйте онлайн!

using System;
using System.Linq;

var S = "";
int I = 0, C = s.Count();
for (; I < C; I++)
    S = Array.Find(
        s, x =>
        s[I].Substring(0, 1).ToUpper() == x.Substring(x.Length - 1).ToUpper()
    ) == null ?
    s[I] :
    S;
for (I = 0; I < C; I++) {
    Console.Write(S + " ");
    S = C > I ? Array.Find(s, x => S.Substring(S.Length - 1).ToUpper() == x.Substring(0, 1).ToUpper()) : "";
}
Хилле
источник