Гарний час для відмови


16

Налаштування

Припустимо, вам задано n запобіжників, 1 ≤ n ≤ 5, кожен з яких довжиною метра, і де кожен запобіжник має відповідну швидкість горіння N метрів за D години.

Запобіжник може бути запалений на одному або з обох кінців, згодом гаситись на одному або обох кінцях, перекривати, повторно гасити і т. Д. Стільки разів, скільки потрібно до повного споживання запобіжника. Ви в змозі запалити і загасити запобіжники миттєво, і ви зможете спостерігати точний момент, коли запобіжник повністю споживається (згоряє).

Запобіжник не може бути розрізаний, а також не може бути запалений ніде, крім його кінців.

Таке налаштування дозволяє створити нескінченно точну систему синхронізації шляхом вимірювання часу між будь-якими двома подіями освітлення / споживання запобіжника. Наприклад, враховуючи два запобіжники зі швидкістю опіку 1 метр на годину, ви можете виміряти рівно 45 хвилин (3/4 години) на

  1. одночасно: запалюйте перший запобіжник на обох кінцях, запалюючи другий запобіжник на одному кінці та маркуючи початок вашого часового інтервалу
  2. запалюючи другий кінець другого запобіжника в той момент, коли перший запобіжник витрачається (через 30 хвилин)
  3. маркування кінця вашого часового інтервалу в той момент, коли буде витрачений другий запобіжник (через 15 хвилин)

Змагання

Враховуючи дробову кількість годин t і набір n дробів, що представляють точну швидкість горіння n запобіжників, напишіть програму або функцію, яка виводить / повертає триєдне значення, якщо t годин можна точно виміряти шляхом систематичного спалювання запобіжників, або a хибне значення в іншому випадку.

Вхід до програми може бути будь-яким із наступних:

  • Аргументи командного рядка форми TN/TD N1/D1 N2/D2 N3/D3 ...
  • рядок форми, TN/TD N1/D1 N2/D2 N3/D3 ...прочитаної з stdinабо еквівалентної
  • рядок форми TN/TD N1/D1 N2/D2 N3/D3 ...передається як аргумент функції
  • масив рядків, ["TN/TD", "N1/D1", "N2/D2", "N3/D3", ...]переданий як аргумент функції

У всіх випадках t = TN/ TD, де TN, TD∈ [1,10000].

Так само у всіх випадках: швидкість спалювання запобіжника i = N i / D i = N<i>/ D<i>, де N<i>, D<i>∈ [1,10] ∀ i .

Ви можете припустити, що завжди буде від 1 до 5 запобіжників (включно), і що всі входи є дійсними та в межах дії. Ви також можете припустити, що всі вхідні дроби наведені найменшими.

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

Оцінка балів

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


Приклад Входи / Виходи

input:  29/6 3/2 2/3 3/5 3/7 7/5
output: true

One solution:
  - light both ends of fuse 1, mark start of interval
  - on fuse 1 consumption: light both ends of fuse 2, light one end of fuse 5
  - on fuse 5 consumption: extinguish one end of fuse 2, light both ends of fuse 3,
    light both ends of fuse 4
  - on fuse 2 consumption: extinguish one end of fuse 3, extinguish both ends of
    fuse 4
  - on fuse 3 consumption: relight one end of fuse 4
  - on consumption of fuse 4: mark end of interval (29/6 hours)

input:  2/1 3/1 5/1 7/1
output: false

input:  5/1 6/1 1/6 9/1 1/9
output: true

One solution:
  - light fuse 1 at one end, light fuse 2 at both ends, light fuse 4 at both ends
  - on fuse 1 consumption: extinguish one end of fuse 2, mark start of interval
  - on fuse 4 consumption: relight one end of fuse 2
  - on fuse 2 consumption: mark end of interval (5 hours)

Щасливого зрощення! :)


@ MartinBüttner Я б припустив, що це буде обмеження числа з плаваючою комою.
hmatt1

2
@ MartinBüttner Я згоден, що це не обмеження вихідного коду. Я не думаю, що [обмежений джерело] відповідає цьому питанню, як це є в даний час.
hmatt1

@chilemagic: Я хотів би звернути увагу на те, що логіка з плаваючою комою не може бути використана, але якщо консенсус полягає в тому, що це не належне використання тегу, я його зніму.
COTO

Тестові випадки занадто великі :)
feersum

5
Лол, я використовую алгоритм O ((n!) ^ 3) для цілей гольфу.
feersum

Відповіді:


8

Пітон 2, 305

Це версія для гольфу. Він практично непридатний для n> 3 , оскільки складність у часі (і просторі) дорівнює 3 n 2 ... насправді це може бути занадто низьким для часу. У будь-якому випадку, функція приймає список рядків.

def f(i):
 Z=range;r=map(__import__('fractions').Fraction,i);R=r[1:];n=len(R);L=[[[1]*n,[0]]];g=0
 for m,p in L: 
  for d in([v/3**i%3for i in Z(n)]for v in Z(3**n)):
    try:x=min(m[i]/R[i]/d[i]for i in Z(n)if m[i]*d[i]>0);L+=[[[m[i]-x*R[i]*d[i]for i in Z(n)],[p[0]+x]+p]]
    except:g|=p[0]-r[0]in p
 return g

Трохи оптимізована версія може закінчити тестові справи за пару хвилин. Це все ж може бути повільним для неможливого n = 5 випадку.

def fLessslow(i):
 Z=range
 r=map(__import__('fractions').Fraction,i)
 R=r[1:]
 n=len(R)
 L=[((1,)*n,(0,))]
 ls = set(L)
 for m,p in L: 
  if p[0]-r[0]in p: return 1
  for d in([v/3**i%3 for i in Z(n)]for v in Z(3**n)):
   if any(d[i] and m[i]<=0 for i in Z(n)):continue
   try:
    x=min(m[i]/R[i]/d[i]for i in Z(n)if m[i]*d[i]>0)
    thing = (tuple(m[i]-x*R[i]*d[i]for i in Z(n)),(p[0]+x,)+p)
    if thing not in ls:L+=[thing];ls.add(thing)
   except:5
 return 0

print fLessslow('5/1 6/1 1/6 9/1 1/9'.split())
print fLessslow('29/6 3/2 2/3 3/5 3/7 7/5'.split())

1
Ніцца, 8 оновлень для помилкового коду: виклик функції за прикладом в описі: print f ('3/4 1/1 1 / 1'.split ()) повертає 0, хоча, як випливає з опису, це вирішимо .
Якубе

@Jakube Дякую за тестування ... це дуже рідко на цьому сайті! Це зафіксовано зараз; Я забув в одному місці ділити на коефіцієнт 1 або 2 залежно від того, скільки кінці мотузки загорілися.
feersum

3

Пітон 2, 331

Це трохи довше, ніж версія feersum, але набагато швидша. Всі тести разом займають близько 3 секунд на моєму ноутбуці. Повний пошук n = 5 займає 10 хвилин. Частина коду схожа на версію feersum, але я навмисно не копіював жоден код.

from fractions import*
f=Fraction
r=range
g=lambda x:h(f(x[0]),[1/f(i)for i in x[1:]],[])
def h(t,x,y):
 for i in r(1,3**len(x)):
  c=[[],[],[]]
  for j in r(len(x)):c[i/3**j%3]+=[x[j]]
  n,b,w=c
  m=min(b+[i/2 for i in w])
  if h(t,[i for i in n+[j-m for j in b]+[j-2*m for j in w]if i],[i+m for i in y]+[m]):return True
 return t in y

Використання:

print g('3/4 1/1 1/1'.split())
print g('29/6 3/2 2/3 3/5 3/7 7/5'.split())
print g('2/1 3/1 5/1 7/1'.split())
print g('5/1 6/1 1/6 9/1 1/9'.split())

Пояснення:

Лямбда-вираз g виконує деяку попередню обробку введення, як перетворення рядків у дроби, відокремлюючи час мети від швидкості запису та обчислення часу спалювання (= 1 / швидкість запису).

Функція h ділить усі часи спалення x на 3 множини n, b і w (n - це незагорання, b - для одного_закінчення і w для обох_закінчення_запилення). Він повторює всі ці домовленості (крім розташування n = x, b = [], w = []), визначає запобіжник з найкоротшою швидкістю горіння (економить час у м) та рекурсивно викликає h із оновленими часом горіння. У y я економлю всі можливі моменти, коли хтось може виміряти за допомогою запобіжників. У рекурсивному виклику ці значення також оновлюються.

Як тільки я знаходжу цінність, він припиняє виклики алла з True.


4
Ви, молоді програмісти Python, зіпсовані вашими вбудованими дробами та великими цілими числами. Ще коли я був юнаком, все, що у нас було, - 1це і 0ми, які нам довелося набирати одночасно за консоллю без монітора. Іноді у нас не було 1с.
COTO
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.