Co jest następne?

15

Biorąc pod uwagę rozdzieloną spacjami listę liczb całkowitych, Twoim zadaniem jest znalezienie następnej liczby całkowitej w sekwencji. Każda liczba całkowita, w sekwencji jest wynikiem nakładania pojedynczej operacji matematycznych ( +, -, *i /) do poprzedniej liczby całkowitej, a każda sekwencja składa się z szeregu zmiennych takich operacji (ale nie więcej niż 10). Żadna sekwencja nie będzie dłuższa niż połowa długości sekwencji liczb całkowitych, więc każda sekwencja operacji pojawi się co najmniej dwa razy w celu potwierdzenia.
Dane wejściowe będą przesyłane przez stdin (lub w promptprzypadku rozwiązań JavaScript).

Oto kilka objaśniających przykładów.

Wejście:

1 3 5 7 9 11

Wynik:

13

Dość łatwe, tym razem. Wszystkie wartości są poprzednimi wartościami +2.

Wejście:

1 3 2 4 3 5 4 6 5 7 6

Ouput:

8

Dwa kroki w tej kolejności, +2a następnie -1.

Wejście:

2 6 7 3 9 10 6 18 19 15 45 46

Wynik:

42

Trzy kroki - *3, +1, -4.

Przypadki testowe

Oto kilka kolejnych przypadków testowych:

Wejście:

1024 512 256 128 64 32 16

Wynik:

8

Wejście:

1 3 9 8 24 72 71 213 639

Wynik:

638

Wejście:

1 2 3 4 5 2 3 4 5 6 3 4 5 6 7

Wynik:

4

Wejście:

1 2 4 1 3 9 5 8 32 27 28 56 53 55 165 161 164 656 651 652 1304

Wynik:

1301

Mam niefarmowane rozwiązanie Scala (42 linie), które opublikuję za kilka dni.

To jest golf golfowy - wygrywa najkrótsza odpowiedź.

Gareth
źródło
Czy podział jest gwarantowany, aby był dokładny?
Peter Taylor
@ Peter Tak. Każdy krok da liczbę całkowitą.
Gareth
Ale jeśli krok to „/ 3”, czy jest gwarantowane, że reszta zawsze będzie wynosić 0?
Peter Taylor
@Peter Tak, reszta zawsze będzie wynosić 0.
Gareth
3
oeis.org
Thomas Eding

Odpowiedzi:

12

Golfscript, 203 138 znaków

~]0{).2$.);[\(;]zip\/zip{.{~-}%.&({-}+\{;{.0={.~\%{.~%{;0}{~/{/}+}if}{~\/{*}+}if}{~!{;}*}if}%.&(\{;;0}/}{\;}if}%.{!}%1?)!{0}*}do\@)\,@%@=~

Używa o wiele więcej ifs niż standardowy program Golfscript, a jego działanie jest dość tajemnicze, więc oto skomentowana (ale nie odznaczona inaczej niż przez dodanie białych znaków i komentarzy) wersja:

~]0
# Loop over guesses L for the length of the sequence
{
    # [x0 ... xN] L-1
    ).
    # [x0 ... xN] L L
    2$.);[\(;]zip
    # [x0 ... xN] L L [[x0 x1][x1 x2]...[x{N-1} xN]]
    \/zip
    # [x0 ... xN] L [[[x0 x1][xL x{L+1}]...][[x1 x2][x{L+1} x{L+2}]...]...]
    {
        # [x0 ... xN] L [[xi x{i+1}][x{i+L} x{i+L+1}]...]
        # Is there an operation which takes the first element of each pair to the second?
        # Copy the pairs, work out each difference, and remove duplicates
        .{~-}%.&
        # Turn the first difference into an operation
        ({-}+\
        # If there was more than one unique difference, look for a multiplication
        {
            ;
            # [x0 ... xN] L [[xi x{i+1}][x{i+L} x{i+L+1}]...]
            # Do something similar, but working out multiplicative factors
            # Note that if we have [0 0] it could be multiplication by anything, so we remove it.
            # However, they can't all be [0 0] or we'd have only one unique difference
            {
                # [0     0   ] =>
                # [0     _   ] => 0     # a "false" value, because it can't possibly be multiplication
                # [a     a.b'] => {b'*}
                # [a'.b  b   ] => {a'/}
                # [_     _   ] => 0     # ditto
                # This is the obvious place to look for further improvements
                .0={.~\%{.~%{;0}{~/{/}+}if}{~\/{*}+}if}{~!{;}*}if
            }%.&
            # If we have one unique multiplication, even if it's false, keep it.
            # Otherwise discard them and replace them with false.
            (\{;;0}/
        }
        # There was only one unique difference. Discard the pairs
        {\;}if
        # operation - one of 0, {d+}, {m*}, {M/}
    }%
    # [x0 ... xN] L [op0 ... op{L-1}]
    # Is any of the operations false, indicating that we couldn't find a suitable operation?
    .{!}%1?
    # [x0 ... xN] L [op0 ... op{L-1}] idxFalse
    # If idxFalse is -1 then all the ops are ok, and we put a false to exit the loop
    # Otherwise one op failed, so we leave the array of ops, which is non-false, to be popped by the do.
    )!{0}*
}do
# [x0 ... xN] L [op0 ... op{L-1}]
\@)\,@%@=~
# op{(len(Xs)-1)%L} (Xs[-1])

Moje oryginalne zgłoszenie zawierało 88 znaków:

~]:x;2.{;).(2base(;{[{--}{@*\.!+/}]=}%[x.(;2$]zip\,<{~++}%x,.@[*x\]zip<{~~}%)\x(;=!}do\;

Jednak to próbuje obliczyć operacje od pierwszego wystąpienia każdego z nich, więc jeśli operacja jest mnożeniem lub dzieleniem, a argument za pierwszym razem wynosi 0, łamie się.

Peter Taylor
źródło
1
Dziękuję bardzo za opublikowanie wyjaśnienia! Szukałem szczegółowych programów do gry w golfa, więc mogę spróbować je lepiej zrozumieć.
migimaru
6

Haskell, 276 261 259 257 243 znaków

Oto moje nieefektywne rozwiązanie. Działa na liczbach całkowitych nieograniczonych (i ograniczonych). To rozwiązanie działa poprawnie z nieprecyzyjnym podziałem (np 5 / 2 = 2.:).

import Control.Monad
main=interact$show.n.q read.words
f=flip
q=map
_%0=0
x%y=div x y
s b=[1..]>>=q cycle.(f replicateM$[(+),(*),(%)]>>=f q[-b..b].f)
m l x s=[y!!l|y<-[scanl(f($))(x!!0)s],x==take l y]
n x=(s(maximum$q abs x)>>=m(length x)x)!!0

Jak to działa: tworzę każdą możliwą sekwencję (możliwych) operacji. Następnie testuję sekwencję wejściową liczb, aby sprawdzić, czy wygenerowana sekwencja utworzy dane wejściowe. Jeśli tak, zwróć następny numer w sekwencji. Kod zawsze zwraca odpowiedź uzyskaną z najkrótszej sekwencji operacji. Dzieje się tak, ponieważ lista sekwencji operacji jest generowana w tej kolejności. Podejmowanie decyzji między więzami jest arbitralne (ale konsekwentne). Na przykład kod zwraca 6lub 8dla sekwencji 2 4.

Nie golfowany:

import Control.Monad

main :: IO ()
main = print . next . map read . words =<< getLine

opSequences :: Integral a => a -> [[a -> a]]
opSequences bound = [1 ..] >>= map cycle . (`replicateM` (ops >>= (`map` args) . flip))
  where
    ops = [(+), (*), \x y -> if y == 0 then 0 else div x y]
    args = [-bound .. bound]

match :: (MonadPlus m, Integral a) => [a] -> [a -> a] -> m a
match ns opSeq = guard (ns == take len ms) >> return (ms !! len)
  where
    n0 = ns !! 0
    len = length ns
    ms = scanl (flip ($)) n0 opSeq

next :: Integral a => [a] -> a
next ns = (opSequences bound >>= match ns) !! 0
  where
    bound = maximum $ map abs ns
Thomas Eding
źródło
Niezły pomysł, jak radzić sobie z nieprecyzyjnym podziałem.
Peter Taylor
To był przypadkowy efekt uboczny. Poszukiwanie rozwiązania było tylko moim początkowym pomysłem, jak rozwiązać ten problem, moim zdaniem było to prostsze zadanie niż obliczenie odpowiedzi.
Thomas Eding,
Jest Control.Monad -> Monadmożliwe A co interact$show.n.q read.words
powiesz na
6

Python, 333 366 ... 315 303 278 269 261 246 znaków

n=map(float,raw_input().split())
y=len(n)-1
l=1
def O(f):
 p,q=n[f:y:l],n[f+1::l]
 for a,b in zip(p,q):
    for x in((b-a).__add__,(b/(a or 1)).__mul__):
     if map(x,p)==q:return x
while 1:
 if all(map(O,range(l))):print int(O(y%l)(n[y]));break
 l+=1

Tworzy operację z pierwszą parą liczb i sprawdza ją na innych parach. Przechowuje wszystkie operacje, a jeśli wszystkie się powiedzą, stosuje odpowiednią operację na ostatnim elemencie listy.

Edytowano: zdał test zła :-) Teraz wyszukaj operację na wszystkich pozycjach.

Ante
źródło
Ładny. Przechodzi wszystkie moje testy, ale nie szczególnie zły Peter Taylor:0 0 1 2 3 6 7 14
Gareth
0 0 0 0 1 0 0 0 0 1nie wyświetla 0.
Thomas Eding,
@trinithis To wejście nie jest zgodne ze specyfikacją. Sekwencja operacji musi zostać powtórzona całkowicie przynajmniej raz.
Gareth,
1
Oooh, oto fajna poprawa: lambda x:x+b-a-> (b-a).__add__. Szkoda, że ​​to tylko jedna postać, dzięki temu wiele się uczę o pythonie.
Nieświadomy
1
Dokonywanie lniejawnie globalnej oszczędności wiele: pastie.org/2416407
Clueless
4

Python, 309 305 295 279 znaków

Obsługuje wszystkie oryginalne przypadki testowe, a także poważny przypadek Petera Taylora 0 0 1 2 3 6 7 14:

l=map(int,raw_input().split())
i=v=0
while v<1:
 v=i=i+1
 for j in range(i):
    p=zip(l[j::i],l[j+1::i])
    d,r=set(q[1]-q[0]for q in p),set(q[1]*1./(q[0]or 1)for q in p if any(q))
    m,n=len(d)<2,len(r)<2
    v*=m+n
    if(len(l)-1)%i==j:s=l[-1]+d.pop()if m else int(l[-1]*r.pop())
print s

Niegolfowane, z wyjściem debugowania (bardzo pomocne w weryfikacji poprawności):

nums = map(int,raw_input().split())
result = None

for i in range(1,len(nums)/2+1):
    print "-- %s --" % i
    valid = 1
    for j in range(i):
        pairs = zip(nums[j::i], nums[j+1::i])
        print pairs

        diffs = [pair[1] - pair[0] for pair in pairs]
        # this is the tough bit: (3, 6) -> 2, (0, 5) -> 5, (5, 0) -> 0, (0, 0) ignored
        ratios = [float(pair[1])/(pair[0] or 1) for pair in pairs if pair[0] != 0 or pair[1] != 0]

        if len(set(diffs))==1:
            print "  can be diff", diffs[0]
            if (len(nums) - 1) % i == j:
                result = nums[-1] + diffs.pop()
        elif len(set(ratios))==1:
            print "  can be ratio", ratios[0]
            if (len(nums) - 1) % i == j:
                result = int(nums[-1]*ratios.pop())
        else:
            print "** invalid period **"
            valid=0
    if valid and result is not None:
        break

print result

Stosowanie:

echo 0 0 1 2 3 6 7 14 | python whatcomesnext.py
bezradny
źródło
Poparłem, choć ściśle mówiąc, dane wejściowe powinny być przekazywane przez stdin, a nie przez argumenty poleceń.
Gareth
To pozwala mi skrócić program o cztery znaki :)
Clueless
Kilka znaków, i = v = 0, a podczas gdy v == 0:
Ante
@ Dziękuję, myślałem, że nie możesz tego zrobić w pythonie, ponieważ przypisanie nie jest wyrażeniem, ale jest pomocnym smakołykiem do gry w golfa. Pomagają również dosłowne tabulatory jako wcięcie drugiego poziomu.
Nieświadomy
Nie jestem Pythonerem, ale wydaje się, że w niektórych wyrażeniach używasz boolanów jako liczb całkowitych, a jednak nie możesz użyć liczby całkowitej jako wartości logicznej w teście while. Czy to prawda? Jeśli tak, to z pewnością v<1działa jako strażnik.
Peter Taylor,
2

Rubinowy 1.9 (437) (521) (447) (477)

Działa dla wszystkich przypadków testowych, w tym „złego”. Zagram w to później.

EDYCJA: Zdałem sobie sprawę, że jest inny przypadek, którego nie załatwiłem poprawnie - kiedy kontynuacja musi użyć operacji „tajemnicy”. Sekwencja 2 0 0 -2 -4 -6początkowo zwracała 0 zamiast -12. Naprawiłem to teraz.

EDYCJA: Naprawiono kilka innych przypadków krawędzi i zmniejszyłem kod do 447.

EDYCJA: Ugh. Musiałem dodać kod do obsługi innych „złych” sekwencji, takich jak0 0 0 6 18 6 12

def v(c,q);t=*q[0];q.size.times{|i|f=c[z=i%k=c.size]
f=c[z]=(g=q[z+k])==0??_:((h=q[z+k+1])%g==0?"*(#{h/g})":"/(#{g/h})")if f==?_
t<<=f==?_?(a=q[i];b=q[i+1].nil?? 0:q[i+1];(a==0&&b==0)||(a!=0&&(b%a==0||a%b==0))?b:0):eval(t.last.to_s+f)}
*r,s=t
(p s;exit)if q==r
end
s=gets.split.map &:to_i
n=[[]]
((s.size-1)/2).times{|i|a,b=s[i,2]
j=["+(#{b-a})"]
j<<=?_ if a==0&&b==0
j<<="*#{b/a}"if a!=0&&b%a==0
j<<="/#{a/b}"if a*b!=0&&a%b==0
n=n.product(j).map(&:flatten)
n.map{|m|v(m*1,s)}}
migimaru
źródło
1

Scala

Oto rozwiązanie, które wymyśliłem:

object Z extends App{var i=readLine.split(" ").map(_.toInt)
var s=i.size
var(o,v,f)=(new Array[Int](s),new Array[Double](s),1)
def d(p:Int,j:Array[Int]):Unit={if(p<=s/2){def t(){var a=new Array[Int](s+1)
a(0)=i(0)
for(l<-0 to s-1){o(l%(p+1))match{case 0=>a(l+1)=a(l)+v(l%(p+1)).toInt
case _=>a(l+1)=(a(l).toDouble*v(l%(p+1))).toInt}}
if(a.init.deep==i.deep&&f>0){f^=f
println(a.last)}}
o(p)=0 
v(p)=j(1)-j(0)
t
d(p+1,j.tail)
o(p)=1
v(p)=j(1).toDouble/j(0).toDouble
t
d(p+1,j.tail)}}
d(0,i)
i=i.tail
d(0,i)}

Nie golfowany:

object Sequence extends App
{
    var input=readLine.split(" ").map(_.toInt)
    var s=input.size
    var (ops,vals,flag)=(new Array[Int](s),new Array[Double](s),1)
    def doSeq(place:Int,ints:Array[Int]):Unit=
    {
        if(place<=s/2) 
        {
            def trysolution()
            {
                var a=new Array[Int](s+1)
                a(0)=input(0)
                for(loop<-0 to s-1)
                {
                    ops(loop%(place+1))match
                    {
                        case 0=>a(loop+1)=a(loop)+vals(loop%(place+1)).toInt
                        case _=>a(loop+1)=(a(loop).toDouble*vals(loop%(place+1))).toInt
                    }
                }
                if(a.init.deep==input.deep&&flag>0)
                {
                    flag^=flag
                    println(a.last)
                }
            }
            ops(place)=0
            vals(place)=ints(1)-ints(0)
            trysolution
            doSeq(place+1,ints.tail)
            ops(place)=1
            vals(place)=ints(1).toDouble/ints(0).toDouble
            trysolution
            doSeq(place+1,ints.tail)
        }
    }
    doSeq(0,input)
    input=input.tail
    doSeq(0,input)
}
Gareth
źródło
Jak to wywołać? echo "0 0 1 2 3 6 7 14" | scala Sequenceutrzymuje czarny ekran.
użytkownik nieznany
@ użytkownik nieznany, scala Sequencea następnie wprowadź sekwencję i naciśnij enter.
Gareth
Ach, napisałeś w komentarzu do pytań, że nie rozwiązujesz tego konkretnego - działa on z echo-potokiem jak powyżej dla pytań, które można rozwiązać.
użytkownik nieznany
1

Scala 936

type O=Option[(Char,Int)]
type Q=(O,O)
type L=List[Q]
val N=None
def t(a:Int,b:Int):Q=if(a>b)(Some('-',a-b),(if(b!=0&&b*(a/b)==a)Some('/',a/b)else N))else
(Some('+',b-a),(if(a!=0&&a*(b/a)==b)Some('*',b/a)else N))
def w(a:Q,b:Q)=if(a._1==b._1&&a._2==b._2)a else
if(a._1==b._1)(a._1,N)else
if(a._2==b._2)(N,a._2)else(N,N)
def n(l:L):Q=l match{case Nil=>(N,N)
case x::Nil=>x
case x::y::Nil=>w(x,y)
case x::y::xs=>n(w(x,y)::xs)} 
def z(l:L,w:Int)=for(d<-1 to w)yield
n(l.drop(d-1).sliding(1,w).flatten.toList)
def h(s:L):Boolean=s.isEmpty||(s(0)!=(N,N))&& h(s.tail)
def j(s:L,i:Int=1):Int=if(h(z(s,i).toList))i else j(s,i+1)
def k(b:Int,o:Char,p:Int)=o match{case'+'=>b+p
case'-'=>b-p
case'*'=>b*p
case _=>b/p}
val e=getLine 
val i=e.split(" ").map(_.toInt).toList
val s=i.sliding(2,1).toList.map(l=>t(l(0),l(1)))
val H=n(s.drop(s.size%j(s)).sliding(1,j(s)).flatten.toList)
val c=H._1.getOrElse(H._2.get)
println (k(i(i.size-1),c._1,c._2))

bez golfa:

type O = Option[(Char, Int)]

def stepalize (a: Int, b: Int): (O, O) = (a > b) match {
   case true => (Some('-', a-b), (if (b!=0 && b * (a/b) == a) Some ('/', a/b) else None)) 
   case false=> (Some('+', b-a), (if (a!=0 && a * (b/a) == b) Some ('*', b/a) else None)) }

def same (a: (O, O), b: (O, O)) = {
  if (a._1 == b._1 && a._2 == b._2) a else
  if (a._1 == b._1) (a._1, None) else 
  if (a._2 == b._2) (None, a._2) else 
  (None, None)}

def intersection (lc: List[(O, O)]): (O, O) = lc match {
  case Nil => (None, None)
  case x :: Nil => x
  case x :: y :: Nil => same (x, y)
  case x :: y :: xs  => intersection (same (x, y) :: xs)} 

def seriallen (lc: List[(O, O)], w: Int= 1) =
  for (d <- 1 to w) yield 
    intersection (lc.drop (d-1).sliding (1, w).flatten.toList)

def hit (s: List[(O, O)]) : Boolean = s match {
  case Nil => true 
  case x :: xs => (x != (None, None)) && hit (xs)}

def idxHit (s: List[(O, O)], idx: Int = 1) : Int =
  if (hit (seriallen (s, idx).toList)) idx else 
    idxHit (s, idx+1)

def calc (base: Int, op: Char, param: Int) = op match {
  case '+' => base + param
  case '-' => base - param
  case '*' => base * param
  case _   => base / param}

def getOp (e: String) = {
  val i = e.split (" ").map (_.toInt).toList
  val s = i.sliding (2, 1).toList.map (l => stepalize (l(0), l(1)))
  val w = idxHit (s)
  val hit = intersection (s.drop (s.size % w).sliding (1, w).flatten.toList)
  val ci = hit._1.getOrElse (hit._2.get)
  val base = i(i.size - 1)
  println ("i: " + i + " w: " + w + " ci:" + ci + " " + calc (base, ci._1, ci._2))
}

val a="1 3 5 7 9 11"
val b="1 3 2 4 3 5 4 6 5 7 6"
val c="2 6 7 3 9 10 6 18 19 15 45 46"
val d="1024 512 256 128 64 32 16"
val e="1 3 9 8 24 72 71 213 639"
val f="1 2 3 4 5 2 3 4 5 6 3 4 5 6 7"
val g="1 2 4 1 3 9 5 8 32 27 28 56 53 55 165 161 164 656 651 652 1304"
val h="0 0 1 2 3 6 7 14"
val i="0 0 0 0 1 0 0 0 0 1 0"

List (a, b, c, d, e, f, g, h, i).map (getOp)

Zawodzi żałośnie u Petera Taylora h, ale nie widzę możliwości uzdrowienia programu w rozsądnym czasie.

nieznany użytkownik
źródło
Że to pomoże, aby zmniejszyć go, jeśli traktować -jako szczególny przypadek +i /jako szczególny przypadek *? Mój sposób na przekazanie danych Petera Taylora (i podobnych) polegał na odcięciu pierwszej liczby w sekwencji i ponownym spróbowaniu. Nie miałem czasu przyjrzeć się, jak działa twój program, aby wiedzieć, czy to pomogłoby w twoim.
Gareth,
Myślę, że to pomogłoby, ale tylko w tym szczególnym przypadku. Seria, która później zwielokrotnia wartość zerową, -1, 0, 0, 1, 2, 3, 6, 7, 14będzie wymagała innego leczenia.
użytkownik nieznany