Блокування комбінованого велосипеда


46

Сценарій

Після довгого робочого дня в офісі і перегляду stackexchange.com , я нарешті виходжу з дверей о 16:58, вже втомившись із днем. Оскільки я все ще лише стажист, теперішній вид транспорту на велосипеді. Я переїжджаю до свого надійного Peugeot Reynolds 501 , але перш ніж я зможу відплисти на ньому, мені потрібно його розблокувати. Замок - це стандартний чотиризначний комбінований замок (0-9) через раму та переднє колесо. Коли я намагаюся не спати, я підтягую руку вгору, щоб увійти в комбінацію. Блокування комбінованого велосипеда

Змагання

Оскільки мої пальці так втомлюються, я хочу повернути замок на правильну комбінацію найменшими рухами. Один рух визначається як обертання на одну позицію (36 градусів), наприклад, є один рух від 5737до 5738. Однак я в змозі схопити до будь-яких трьох послідовних кілець одночасно і обертати їх як одне , що вважається лише одним рухом. Наприклад , існує також тільки один рух від 5737до 6837або 5626. Перехід від 5737до 6838- це не один рух, оскільки цифри числа 1,2 та 4 перемістилися в одному напрямку, але незалежно від цифри 3.

Тому для даної комбінації я бачу на велосипедному блокуванні (будь-яке 4-розрядне ціле число), яку найменшу кількість рухів я можу зробити, щоб розблокувати його, і так, я можу обертатись у будь-якому напрямку в будь-який час. Під цим я маю на увазі, що я можу повернути одні цифри в одну сторону, а інші цифри в іншу сторону: не всі мої рухи будуть для кожного розблокування за годинниковою або за годинниковою стрілками.

Оскільки я лінивий, мій код розблокування - 0000.

Це код гольфу, я не можу заважати писати багато коду, тому виграє найкоротша програма в кількості байтів.

Введення з stdin, і ваш код повинен виводити комбінації, які я бачу на кожному кроці після кожного руху, включаючи 0000 в кінці. Кожен з результатів комбінацій повинен бути розділений пробілом / новою лінією / комою / періодом / амперсом.

Приклади

Input: 1210
0100
0000

Input: 9871
9870
0980
0090
0000

Input: 5555
4445&3335&2225&1115&0005&0006&0007&0008&0009&0000

Input: 1234
0124 0013 0002 0001 0000

Я спробував розмістити це на http://bicycles.stackexchange.com , але їм це не сподобалось ...

Відмова: Перший гольф, так що все, що порушено / будь-яка відсутність інформації, дайте мені знати! Також я робив усі приклади вручну, тому можуть бути рішення, які передбачають менше рухів!

EDIT: Для відповідей, які мають кілька шляхів рішення з однаковою кількістю рухів (практично всі вони), немає кращого рішення.


18
Ласкаво просимо до PPCG; дуже приємний перший виклик!
Дверна ручка

4
Це виглядає солідно для мене! Ласкаво просимо до PPCG!
Mego

1
Приємний виклик. Чи можу я запитати, яким повинен бути результат для справ: 7478 та 3737?
noisyass2

1
@ noisyass2 Дякую; Відповідь flawr дає наступне: 7478 8588 9698 0708 0808 0908 0008 0009 0000 та 3737 2627 1517 0407 0307 0207 0107 0007 0008 0009 0000 Якщо дивитися лише на 3737, це має сенс: Дивлячись лише на перші 3 цифри: Якщо я переміщу всі перші три одночасно потрібно 3 руху для цифр 1 і 3, а потім ще 4 руху для цифри 2, таким чином, всього сім. Якщо я рухаюся кожен окремо, кожен робить 3 ходи, тобто 9 рухів.
Луї

1
Мені цікаво, чи може заголовок «Комбінований замок» (або «Велосипедний замок») залучити більше глядачів.
DavidC

Відповіді:


10

Матлаб, 412 327 байт

Гольф (спасибі @AndrasDeak за гольф s!):

s=dec2bin('iecbmgdoh'.'-97)-48;s=[s;-s];T=1e4;D=Inf(1,T);P=D;I=NaN(T,4);for i=1:T;I(i,:)=sprintf('%04d',i-1)-'0';end;G=input('');D(G+1)=0;for k=0:12;for n=find(D==k);for i=1:18;m=1+mod(I(n,:)+s(i,:),10)*10.^(3:-1:0)';if D(m)==Inf;D(m)=k+1;P(m)=n-1;end;end;end;end;n=0;X='0000';while n-G;n=P(n+1);X=[I(n+1,:)+48;X];end;disp(X)

Цей код використовує деяке динамічне програмування для пошуку найкоротшого "шляху" від заданого числа до 0000використання лише можливих кроків. Виклик - це в основному пріоблема найкоротшого шляху (як альтернатива, можливо, ви можете розглянути кроки як групу комутатів), але складність полягала в ефективній реалізації. Основні структури - це два масиви 10000 елементів, один для зберігання кількості кроків, щоб дістатися до цього індексу, інший для зберігання вказівника на попередній 'вузол' у нашому графіку. Він одночасно обчислює "шляхи" до всіх інших можливих чисел.

Приклади:

9871
0981
0091
0001
0000

1210
0100
0000

Examples by @noisyass:

7478
8578
9678
0788
0899
0900
0000

3737
2627
1517
0407
0307
0207
0107
0007
0008
0009
0000

Own Example (longest sequence, shared with 6284)

4826
3826
2826
1826
0826
0926
0026
0015
0004
0003
0002
0001
0000    

Повний код (включаючи деякі коментарі):

%steps
s=[eye(4);1,1,0,0;0,1,1,0;0,0,1,1;1,1,1,0;0,1,1,1];
s=[s;-s];


D=NaN(1,10000);%D(n+1) = number of steps to get to n
P=NaN(1,10000);%P(n+1) was last one before n

I=NaN(10000,4);%integer representation as array
for i=0:9999; 
    I(i+1,:)=sprintf('%04d',i)-'0';
end

G=9871; % define the current number (for the golfed version replaced with input('');
D(G+1)=0;
B=10.^(3:-1:0); %base for each digit

for k=0:100; %upper bound on number of steps;
    L=find(D==k)-1;
    for n=L; %iterate all new steps
        for i=1:18; %search all new steps
            m=sum(mod(I(n+1,:)+s(i,:),10) .* [1000,100,10,1]);
            if isnan(D(m+1))
                D(m+1) = k+1;
                P(m+1)=n;
            end
        end
    end
end
n=0;%we start here
X=[];
while n~=G
    X=[I(n+1,:)+'0';X];
    n=P(n+1);
end
disp([I(G+1,:)+'0';X,''])

Приємно! Будучи в основному користувачем Matlab, мені було цікаво, наскільки це буде добре.
Луї

1
Для введення 6444ваш код дає 6444 7554 8664 9774 0884 0994 0004 0003 0002 0001 0000, тоді як я вважаю, що відповідь - 6444 6333 6222 6111 6000 7000 8000 9000 0000. Моя відповідь - 8 кроків, ваш - 10. Я не бачу проблема, і, схоже, вона існує як у версії для гольфу, так і в безгоні. Це зафіксовано в останньому редагуванні.
Луї

1
Я просто виправив невелику помилку в коді. В sостанньому ряду має бути [0,1,1,1]. Тоді ви отримаєте і 8-крокове рішення! Вибачте за незручності =)
недолік

1
@Lui Є кімната для матлаб / октави , серед іншого - це якась база для матч-гольфу MATL.
недолік

1
за 4826 рік, я знайшов рішення з 11 переїздів: 4826 3716 2606 1506 0406 0306 0206 0106 0007 0008 0009 0000
noisyass2

4

Пакетна - 288 байт

Навіть якщо ви сказали , що вони повинні бути послідовними (кільця), я вважаю , з допомогою логіки (наслідуючи приклад) , що я можу пропустити середній, так як від 1234до 0224.

set / px =
встановити a =% x: ~ 0,1% & встановити b =% x: ~ 1,1% & встановити c =% x: ~ 2,1% & встановити d =% x: ~ 3,1%
: l
@echo% x% & if% a% == 0 (якщо% d% NEQ 0 set / ad = d-1) else set / aa = a-1
@if% b% NEQ 0 set / ab = b-1
@if% c% NEQ 0 set / ac = c-1
@if% x% NEQ 0000 встановити x =% a %% b %% c %% d% & goto l

Це моє Batch рішення: 236 байт.


Редагувати: виправлене рішення

set / px =
встановити a =% x: ~ 0,1% & встановити b =% x: ~ 1,1% & встановити c =% x: ~ 2,1% & встановити d =% x: ~ 3,1%
: l
@echo% x% & встановити k = 1 & якщо% a% == 0 (якщо% d% NEQ 0 встановити / ad = d-1 & встановити k = 0) else set / aa = a-1 & встановити k = 1
@if% b% NEQ 0, якщо% k% == 1 set / ab = b-1 & set k = 0
@if% c% NEQ 0, якщо% k% == 0 set / ac = c-1
@if% x% NEQ 0000 встановити x =% a %% b %% c %% d% & goto l

Нове рішення (зафіксовано відповідно до коментарів, що лежать в основі) важить 288 байт.


Я не дивився на вашу відповідь дуже глибоко, але я намагаюся слідувати вашій логіці в першому абзаці. Який приклад конкретно ви маєте на увазі? І твій приклад переходу 1234до 0224- це не один рух. Ідея полягає в тому, що за допомогою лише двох пальців я можу вхопити до трьох кілець підряд одним рухом.
Луї

Я мав на увазі, якщо ви можете перемістити 3 послідовних кільця, розумно думати, що ви можете також перемістити перше і третє, уникаючи другого. Або я повинен змінити свій код?
шуміть

Ваше припущення неправильне; ви повинні змінити свій код. Чи бачите ви логіку, як це пояснено у вищезазначеному коментарі?
Луї

Код виправлено. Я перевірив кілька різних типів комбінацій, і мені здається, що це завжди проходить коротший шлях.
шуміть

Здається, це враховується лише вниз, тому для комбінацій з високою кількістю потрібно більше часу (наприклад, 18 кроків за 9999)
fabi

2

Haskell - 310 байт

import Data.Char
import Data.List
r=replicate
h=head
a x=map(:x)[map(`mod`10)$zipWith(+)(h x)((r n 0)++(r(4-j)q)++(r(j-n)0))|j<-[1..3],n<-[0..j],q<-[1,-1]]
x!y=h x==h y
x#[]=(nubBy(!)$x>>=a)#(filter(![(r 4 0)])x)
x#y=unlines.tail.reverse.map(intToDigit<$>)$h y
main=do x<-getLine;putStrLn$[[digitToInt<$>x]]#[]

Це працює за допомогою багаторазового складання нового списку комбінацій, застосовуючи кожен можливий поворот до кожної вже досягнутої комбінації, поки одна з них не стане правильною комбінацією. Дублікати видаляються зі списку для кожної ітерації, щоб запобігти зростанню використання пам'яті в експоненціальному масштабі.

Як рішення грубої сили, це дуже неефективно і може зайняти кілька хвилин.

Я не маю великого досвіду роботи з Haskell, тому, можливо, щось можна зробити краще.


Здається, це міцна основа для вашого підходу. Я не маю досвіду роботи з Haskell, а також (що мені відомо) жодних засобів його складання / запуску. Швидкий google не дає мені ніде, і я можу спробувати його. Чи можете ви надати посилання, яке дозволяє мені його спробувати? Дякую.
Луй

@Lui Це може бути складено за допомогою компілятора Glasgow Haskell , але окрім завантаження та використання, я не знаю жодного способу його запустити.
faubi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.