Digital River (soluzione più breve e più veloce)


9

Questa è la mia prima domanda, quindi spero che vada bene.

Sfondo:

Non sono i fiumi a cui potresti pensare. La domanda ruota attorno al concetto di fiumi digitali. Un fiume digitale è una sequenza di numeri in cui il numero seguente nè npiù la somma delle sue cifre.

Spiegazione:

12345 è seguito da 12360 poiché 1 + 2 + 3 + 4 + 5 = 15 e quindi 12345 + 15 dà 12360. allo stesso modo 145 è seguito da 155. Se il primo numero di un fiume digitale è Mlo chiameremo fiume M.

Ad esempio: il fiume 480 è la sequenza che inizia {480.492.507.519 ....} e il fiume 483 è la sequenza che inizia {483.498.519, ....}. Ruscelli e fiumi normali possono incontrarsi, e lo stesso vale per i fiumi digitali. Ciò accade quando due fiumi digitali condividono alcuni degli stessi valori.

Esempio:

Il fiume 480 incontra il fiume 483 a 519. Il fiume 480 incontra il fiume 507 a 507 e non incontra mai il fiume 481. Ogni fiume digitale alla fine incontrerà il fiume 1, il fiume 3 o il fiume 9.

Scrivi un programma che può determinare per un dato numero intero nil valore in cui il fiume nincontra per primo uno di questi tre fiumi.

Ingresso

L'input può contenere più casi di test. Ogni caso di test occupa una riga separata e contiene un numero intero n( 1 <= n <= 16384). Un caso di test con valore di 0for ntermina l'input e questo caso di test non deve essere elaborato.

Produzione

Per ogni caso di test nell'ingresso, prima uscita il numero del caso di test (a partire da 1) come mostrato nell'output del campione. Quindi su una linea separata emette la linea "prima incontra il fiume x a y". Qui y è il valore più basso in cui river nincontra prima river x(x = 1 o 3 o 9). Se river nincontra river xa yper più di un valore di x, genera il valore più basso. Stampa una riga vuota tra due casi di test consecutivi.

Caso di prova

Ingresso:

86
12345
0

Produzione:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

punteggio:

Vince l'algoritmo più veloce. In caso di pareggio. Vincerà quello con un codice più breve.

Grazie a mbomb007 per aver segnalato il mio errore.

ps: voglio avere la soluzione più veloce piuttosto che la più piccola. Ho anche una mia soluzione che è lenta. Per quello sguardo qui .

Nota:

Userò questo per il test del codice. E controllo delle prestazioni.


3
Non sono sicuro che puoi segnare in quel modo. Cosa succede se il codice di qualcuno è O (log (log n))? Non puoi coprirli tutti, quindi devi solo dire che l'algoritmo più veloce vince, ma in caso di pareggio, vince il codice più corto e vince per primo pubblicato nel caso entrambi abbiano la stessa lunghezza.
mbomb007,

3
Non riesco a trovare nulla sul copyright o sull'usabilità delle vecchie sfide ACM-ICPC, ma posso trovare questa sfida sul sito dell'archivio. È consentito utilizzare qui?
Geobits,

1
Questo non ha nulla a che fare con il copyright. In caso di dubbio, la cosa più semplice è di solito inviare un'e-mail al proprietario del sito e chiedere.
Geobits,

3
" Se l'ultima cifra di un fiume digitale è Mla chiameremo fiumeM " non ha senso per due ragioni: in primo luogo, se un fiume è una sequenza infinita di numeri, allora non ha un'ultima cifra; e in secondo luogo, nel paragrafo successivo riverM indica il fiume che inizia con il numero M.
Peter Taylor,

2
Dalla domanda CR.SE collegata, sembra che un river sia il numero che inizia con la serie, ma ecco l'ultima cifra. Che è corretto?
Celeo,

Risposte:


3

C, 320 294 byte

Compilare con -std = c99

#include<stdio.h>
int s(int i){for(int j=i;j;j/=10)i+=j%10;return i;}int main(){int c=0,i;while(scanf("%d",&i)){c++;if(!i)continue;int j,o[]={1,3,9},p[]={1,3,9};Q:for(j=0;j<3;j++){if(o[j]==i)goto D;else if(o[j]<i){o[j]=s(o[j]);goto Q;}}i=s(i);goto Q;D:printf("Case #%d\n\nfirst meets river %d at %d\n\n",c,p[j],o[j]);}}

Ungolfed:

#include <stdio.h>

int s(int i)
{
    for(int j = i; j; j /= 10)
        i += j % 10;
    return i;
}

int main()
{
    int c = 0, i;
    while(scanf("%d", &i))
    {
        c++;
        if(!i)
            continue;
        int j,o[]={1,3,9},p[]={1,3,9};
        Q: for(j = 0; j < 3; j++)
        {
            if(o[j] == i)
                goto D;
            else if(o[j] < i)
            {
                o[j] = s(o[j]);
                goto Q;
            }
        }
        i = s(i);
        goto Q;
        D: printf("Case #%d\n\nfirst meets river %d at %d\n\n", c, p[j], o[j]);
    }
}

Provalo!

In sostanza, i fiumi "target" vengono aumentati fino a quando non sono più grandi del fiume su cui stiamo testando, e successivamente viene aumentato il fiume di prova. Questo viene ripetuto fino a quando il fiume di prova non è uguale a qualche altro fiume.

Non sto leggendo i parametri dalla riga di comando in questo programma e non sono sicuro che tu debba farlo. Ora puoi passare i parametri a STDIN. È possibile terminare passando un input non numerico.

Dannatamente, battuto di mezz'ora.


Sto lavorando su casi di test per ora. Solo 3 casi di test di input non saranno molto adatti.
Kishan Kumar,

per favore, ti dispiacerebbe prendere input da stdin.
Kishan Kumar,

3

JavaScript (ES6)

Questa è una risposta abbastanza veloce usando un linguaggio piuttosto lento. In realtà, l'esecuzione del tempo non dovrebbe essere un problema nell'uso di qualsiasi linguaggio con tabelle hash. Tutti i miei test sotto i 100 ms.

Metodo anonimo con l'elenco di casi di test come parametro di input.

F=cases=>{
  var t0 = +new Date
  var result = 0
  var spots = []
  var top=[,1,3,,9]
  var rivers=[,1,3,1,9,1,3,1]
  cases.forEach((n,i)=>{
    var found = result = spots[n]
    for (;!found;)
    {
      found = top.some((v,i)=>{
        for(;spots[v] |= i, v<n; top[i] = v)
          [...v+''].forEach(d=>v-=-d)
        return result = v-n ? 0 : i;
      }) || (
        [...n+''].forEach(d=>n-=-d),
        result = spots[n]
      )
    }  
    console.log(`Case #${i+1}\nfirst meets river ${rivers[result]} at ${n}`)
  })  
  return 'Time (ms) ' + (new Date-t0)
}  

console.log(F([86, 12345, 123, 456, 789, 16384]))


1

Java 7, 519 505 byte

import java.util.*;String c(int i){if(i<=0)return"";ArrayList<Long>r=f(1),s=f(3),t=f(9),x=f(i);String z="first meets river ";for(int j=0;j<r.size();j++){long u=r.get(j),v=s.get(j),w=t.get(j);if(x.contains(u))return z+1+" at "+u;if(x.contains(v))return z+3+" at "+v;if(x.contains(w))return z+9+" at "+w;}return"";}ArrayList f(long i){ArrayList<Long>l=new ArrayList();l.add(i);for(long j=0,x;j<9e4;j++){x=l.get(l.size()-1);for(char c:(x+"").toCharArray())x+=new Long(c+"");l.add(x);if(x>16383)return l;}return l;}

Sì, è lungo, brutto e senza dubbio può essere completamente cambiato in code-golf più .. Sono distratto e stanco, quindi forse dovrei semplicemente cancellarlo di nuovo ..
È stata una sfida piuttosto difficile ad essere onesti. Ma almeno hai la tua prima risposta ..;) (Che potrebbe anche essere più lungo del tuo programma C ++ non golf originale .. xD)

Casi non testati e test:

Provalo qui.

import java.util.*;
class M{
  static String c(int i){
    if(i <= 0){
      return "";
    }
    ArrayList<Long> r = f(1),
                    s = f(3),
                    t = f(9),
                    x = f(i);
    String z = "first meets river ",
           y = " at ";
    for(int j = 0; j < r.size(); j++){
      long u = r.get(j),
           v = s.get(j),
           w = t.get(j);
      if(x.contains(u)){
        return z+1+y+u;
      }
      if(x.contains(v)){
        return z+3+y+v;
      }
      if(x.contains(w)){
        return z+9+y+w;
      }
    }
    return "";
  }

  static ArrayList f(long i){
    ArrayList<Long> l = new ArrayList();
    l.add(i);
    for(long j = 0, x; j < 9e4; j++){
      x = l.get(l.size() - 1);
      for(char c : (x + "").toCharArray()){
        x += new Long(c+"");
      }
      l.add(x);
      if(x > 16383){
        return l;
      }
    }
    return l;
  }

  public static void main(String[] a){
    System.out.println(c(86));
    System.out.println(c(12345));
    System.out.println(c(0));
  }
}

Produzione:

first meets river 1 at 101
first meets river 3 at 12423
(empty output)

Confronterò il tuo programma con il mio. Pubblicherò anche la mia soluzione. Perché usare un linguaggio lento. Usa qualsiasi linguaggio veloce.
Kishan Kumar,

Ho notato solo il tag dell'algoritmo più veloce in seguito .. Pubblico sempre qui le risposte di code-golf Java 7 .. Di sicuro non vincerà né nel più breve né nel più veloce però .. A proposito, il tuo rextester fornisce errori quando dovrebbe solo dare avvisi per mancanza di cast / inizializzazione del tipo .. Funziona su ideone (e in Eclipse IDE).
Kevin Cruijssen,

ok. fammi vedere. rextester fornisce i tempi di compilazione e di esecuzione. Quindi l'ho usato
Kishan Kumar il

bene questo è un problema qui. Cercherò un altro compilatore online che fornisca i tempi di compilazione e di esecuzione
Kishan Kumar,

@KishanKumar Ho aggiunto i cast nel mio codice, il che non dovrebbe influire sul tempo dopo. Ecco il codice funzionante del rextester con il risultato: Compilation time: 0.62 sec, absolute running time: 0.14 sec, cpu time: 0.11 sec, memory peak: 22 Mb, absolute service time: 0,77 secper me localmente. Quindi sì, è piuttosto lento ..
Kevin Cruijssen,

1

Scala, 774 byte

Fiddle: http://scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b

Non mi va di giocare a golf. Trova una soluzione al problema posto entro 50ms

L'utilizzo potrebbe non essere esattamente quello che desideri:

scala river.scala

Ora puoi inserire continuamente numeri seguiti da un invio. E termina il programma con 0. Il risultato verrà stampato non appena premi Invio.

io.Source.stdin.getLines.map(_.toInt)
  .takeWhile(_ != 0)
  .map(stream(_).takeWhile(_ < 16383))
  .zipWithIndex
  .map { cur =>
    Seq(1, 3, 9).map { i =>
      val s = stream(i).takeWhile(_ < 16383)
      (cur._2+1, i, s.intersect(cur._1).headOption)
    }
  }.foreach { opts =>
    val options = opts.filterNot(_._3.isEmpty)

    if(options.isEmpty) {
      println("No result")
    } else {
      val opt = options(0)
      println(s"Case #${opt._1}\n\nfirst meets ${opt._2} at ${opt._3.get}\n\n")
    }
  }

def stream(i:Int): Stream[Int] = {
  def sub: Int => Stream[Int] = {
    i => i #:: sub(a(i))
  }
  sub(i)
}

def a(i:Int): Int = i + i.toString.map{_.asDigit}.sum

Non so molto di Scala. Quindi, per favore, potresti modificare il codice che sarà secondo rextester.com/l/scala_online_compiler
Kishan Kumar

Ho provato a inserirlo ma è scaduto durante la compilazione.
AmazingDreams

ok @AmazingDreams
Kishan Kumar

@KishanKumar anche il valore predefinito una volta fuori quindi il sito sembra essere rotto per scala
AmazingDreams

@KisthanKumar Usa questo scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b anche se non supporta lo stdin, quindi ho dovuto cambiare alcune cose minori.
AmazingDreams,

1

C, 228 283 300 byte

Questa è una mod del codice di Yakov per sfruttare gli schemi del fiume. Questo lo rende ~ 3 volte più veloce. Inoltre, i numeri interi senza segno evitano la cltodpenalità sui computer a 64 bit, quindi sono più lunghi di alcuni byte ma leggermente più veloci.

#define sum(z) for(y=z;y;y/=10)z+=y%10;
n,x;main(){unsigned i,j,y;while(scanf("%d",&i)){if(i){j=x=1+!(i%3)*2+!(i%9)*6;do{while(j<i)sum(j)}while(j^i&&({sum(i)i;}));printf("Case #%u\n\nfirst meets river %u at %u\n\n",++n,x,i);}}}

Ungolfed:

#define sum(z) for(y=z;y;y/=10)z+=y%10;
n, x;
main() {
    unsigned i, j, y;
    while(scanf("%d", &i)) {
        if(i){
            j = x = 1 + !(i%3)*2 + !(i%9)*6;
            do{
                while (j < i) sum(j)
            }
            while(j^i&&({sum(i)i;}));
            printf("Case #%u\n\nfirst meets river %u at %u\n\n", ++n, x, i);
        }
    }
}

Spiegazione:

j = x = 1 + !(i%3)*2 + !(i%9)*6;

Questo seleziona il fiume corretto. Il fiume 1 incontra ogni altro fiume, quindi lo usiamo come caso di ripiego. Se 3 è il massimo comune divisore del test river, selezioniamo river 3 ( 1 + !(i%3)*2). Se 9 è il massimo comune divisore del fiume test, sovrascriviamo i valori precedenti e selezioniamo il fiume 9.

Perché funziona? Il fiume 9 va 9, 18, 27, 36, ecc. Questo passo di un multiplo di 9 ogni volta, quindi sarà sempre il percorso più breve verso un fiume gemello. Il fiume 3 farà un passo di un multiplo di 3 ogni volta: 3, 6, 12, 15, 21, ecc. Mentre i fiumi che sono un multiplo di 9 sono anche un multiplo di 3, li scegliamo prima come fiume 9, lasciando solo il multipli di 3. Il resto incontrerà prima il fiume 1: 1, 2, 4, 8, 16, 23, 28, ecc.

Dopo aver selezionato il nostro fiume corretto, calpestiamo i due fiumi finché non si incontrano.


1

Python 3, 144 byte

r,a,b,c,i={int(input())},{1},{3},{9},1
while i:
  for x in r,a,b,c:t=max(x);x|={sum(int(c)for c in str(t))+t}
  if r&(a|b|c):i=print(*r&(a|b|c))

0

C

Molto semplice, sembra così lungo perché ho srotolato tutti e 3 i fiumi. Prima genera i 3 fiumi fino a RIVER_LENGTH(che spero sia abbastanza grande), quindi per ogni passo Nfa una ricerca binaria su tutti e tre i flussi per vedere se si trova in uno di essi. Questo funziona perché gli stream sono già ordinati, quindi possiamo fare il check-in dei contenuti log(n).

#include <stdio.h>

#define RIVER_LENGTH 10000

int main() {
    int num_cases;
    scanf("%d", &num_cases);
    int cases[num_cases];
    int N;
    int s1[RIVER_LENGTH] = {1};
    int s3[RIVER_LENGTH] = {3};
    int s9[RIVER_LENGTH] = {9};
    int i;
    int temp;

    for (i = 1; i < RIVER_LENGTH; i++) {
        s1[i] = temp = s1[i-1];
        while (temp) {
            s1[i] += temp % 10;
            temp /= 10;
        }
    }

    for (i = 1; i < RIVER_LENGTH; i++) {
        s3[i] = temp = s3[i-1];
        while (temp) {
            s3[i] += temp % 10;
            temp /= 10;
        }
    }

    for (i = 1; i < RIVER_LENGTH; i++) {
        s9[i] = temp = s9[i-1];
        while (temp) {
            s9[i] += temp % 10;
            temp /= 10;
        }
    }

    int start;
    int end;
    int pivot;

    for (i=1; i <= num_cases; i++) {
        scanf("%d", &cases[i]);
    }

    for (i=1; i <= num_cases; i++) {
        printf("Case #%d\n\n", i);
        N = cases[i];

        while (1) {

            temp = N;
            while (temp) {
                N += temp % 10;
                temp /= 10;
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s1[pivot] == N) {
                    printf("first meets river 1 at %d\n\n", N);
                    goto case_done;
                } else if (N < s1[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s3[pivot] == N) {
                    printf("first meets river 3 at %d\n\n", N);
                    goto case_done;
                } else if (N < s3[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }

            start = 0;
            end = RIVER_LENGTH;
            pivot = 1;

            while (end != start && pivot != RIVER_LENGTH - 1) {
                pivot = start + ((end - start) >> 1);
                if (s9[pivot] == N) {
                    printf("first meets river 9 at %d\n\n", N);
                    goto case_done;
                } else if (N < s9[pivot]){
                    end = pivot;
                } else {
                    start = pivot+1;
                }
            }
        }

        case_done:;

    }
}

Per prima cosa ci vuole un numero per il numero di casi, invece di usarlo 0per delimitare la fine degli input, perché sai, C. Questo è solo per comodità e non influisce davvero su nulla, quindi spero che vada bene.


Questo programma raggiunge un limite di tempo superato su ideone sugli input 86.12345,0
Kishan Kumar,

ideone.com/mHCeef ecco il link. E dà un segnale di uccisione in uscita su rextester
Kishan Kumar,

@KishanKumar Ci vuole prima un numero per il numero di casi, invece di usare 0 per delimitare la fine degli input, perché sai, C. Questo è solo per comodità e non influisce davvero su nulla, quindi spero che vada bene.
Maltysen,

@KishanKumar invece prova questo: rextester.com/XRJK89444
Maltysen

va bene. Nessun problema. Ma dovrò scrivere uno script aggiuntivo per il tuo programma. Come devo prendere il tempo medio di tutta la gamma di input.
Kishan Kumar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.