Digital River (solução mais curta e mais rápida)


9

Esta é a minha primeira pergunta, por isso espero que corra bem.

Fundo:

Não são os rios que você pode estar pensando. A questão gira em torno do conceito de rios digitais. Um rio digital é uma sequência de números em que o número a seguir né nmais a soma de seus dígitos.

Explicação:

12345 é seguido por 12360, já que 1 + 2 + 3 + 4 + 5 = 15 e, portanto, 12345 + 15 fornece 12360. Da mesma forma, 145 é seguido por 155. Se o primeiro número de um rio digital for M, o chamaremos de rio M.

Por exemplo: rio 480 é o início da sequência {480,492,507,519 ....} e rio 483 é a sequência que começa {483,498,519, ....}. Córregos e rios normais podem se encontrar, e o mesmo vale para rios digitais. Isso acontece quando dois rios digitais compartilham alguns dos mesmos valores.

Exemplo:

O rio 480 encontra o rio 483 em 519. O rio 480 encontra o rio 507 em 507 e nunca encontra o rio 481. Todo rio digital acaba encontrando o rio 1, o rio 3 ou o rio 9.

Escreva um programa que possa determinar para um número inteiro no valor em que o rio nencontra primeiro um desses três rios.

Entrada

A entrada pode conter vários casos de teste. Cada caso de teste ocupa uma linha separada e contém um número inteiro n( 1 <= n <= 16384). Um caso de teste com o valor de 0for nfinaliza a entrada e esse caso de teste não deve ser processado.

Resultado

Para cada caso de teste na entrada, primeiro imprima o número do caso de teste (começando em 1), como mostrado na saída de amostra. Em uma saída de linha separada, a linha "encontra primeiro o rio x em y". Aqui y é o valor mais baixo onde o rio nencontra o rio pela primeira vez x(x = 1 ou 3 ou 9). Se o rio nencontrar o rio xcom ymais de um valor de x, produza o valor mais baixo. Imprima uma linha em branco entre dois casos de teste consecutivos.

Caso de teste

Entrada:

86
12345
0

Resultado:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

Pontuação:

O algoritmo mais rápido vence. Em caso de empate. Aquele com código mais curto vencerá.

Obrigado a mbomb007 por apontar o meu erro.

ps: Eu quero ter a solução mais rápida do que a menor. Eu também tenho uma solução minha que é lenta. Para esse olhar aqui .

Nota:

Vou usar isso para teste de código. E verificação de desempenho.


3
Não tenho certeza de que você possa marcar dessa maneira. E se o código de alguém for O (log (log n))? Você não pode cobrir todos eles; portanto, basta dizer que o algoritmo mais rápido vence, mas em caso de empate, o código mais curto vence e o primeiro ganha, caso ambos tenham o mesmo comprimento.
mbomb007

3
Não consigo encontrar nada sobre direitos autorais ou usabilidade dos antigos desafios do ACM-ICPC, mas posso encontrar esse desafio no site do arquivo. É permitido usar aqui?
Geobits

11
Isso não tem nada a ver com direitos autorais. Em caso de dúvida, o mais fácil é enviar um e-mail aos proprietários do site e perguntar.
Geobits

3
" Se o último dígito de um rio digital for Mo nome de rioM " não faz sentido por duas razões: primeiro, se um rio é uma sequência infinita de números, ele não tem um último dígito; e segundo, no próximo parágrafo rioM significa o rio começando em número M.
Peter Taylor

2
A partir da pergunta CR.SE vinculada, parece que o rio é o número que começou na série, mas aqui está o último dígito. Qual é correto?
Celeo 16/09

Respostas:


3

C, 320 294 bytes

Compilar com -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]);
    }
}

Experimente!

Essencialmente, os rios "alvo" são aumentados até que sejam maiores que o rio contra o qual estamos testando e depois o rio de teste aumenta. Isso é repetido até que o rio de teste seja igual a outro rio.

Não estou lendo parâmetros na linha de comando deste programa e não tenho certeza se você deveria. Agora você pode passar parâmetros para STDIN. Você pode finalizar passando uma entrada não numérica.

Também danado, espancado por meia hora.


Estou trabalhando em casos de teste por enquanto. Apenas 3 casos de teste de entrada não serão muito adequados.
Kishan Kumar

por favor, você se importaria de receber informações de stdin.
Kishan Kumar

3

JavaScript (ES6)

Esta é uma resposta bastante rápida, usando uma linguagem bastante lenta. Realmente, o tempo de execução não deve ser um problema ao usar qualquer idioma com tabelas de hash. Todos os meus testes com menos de 100 ms.

Método anônimo com a lista de casos de teste como parâmetro de entrada.

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 bytes

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;}

Sim, é longo, feio e sem dúvida pode ser completamente alterado para codificá-lo mais .. Estou ao mesmo tempo distraído e cansado, talvez devesse excluí-lo novamente ..
Foi um desafio muito difícil ser honesto. . Mas pelo menos você tem sua primeira resposta ..;) (que pode até ser maior que o seu programa C ++ original e não destruído .. xD)

Casos não testados e de teste:

Experimente aqui.

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));
  }
}

Resultado:

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

Vou comparar o seu programa com o meu. Também vou postar minha solução. Por que usar uma linguagem lenta. Use qualquer linguagem rápida.
Kishan Kumar

Eu só notei a tag do algoritmo mais rápido mais tarde .. Eu sempre posto respostas de código-golfe do Java 7 aqui .. Definitivamente, não vai ganhar nem no menor nem no mais rápido. Mas, o rextester comete erros quando só deve dar avisos por falta de projeções / inicializações de tipo .. Funciona em ideone (e no Eclipse IDE).
Kevin Cruijssen

Está bem. deixe-me ver. O rextester fornece tempo de compilação e tempo de execução. Então eu usei
Kishan Kumar

Bem, isso é um problema aqui. Vou procurar outro compilador on-line que dá o tempo e execução tempo de compilação
Kishan Kumar

@KishanKumar Adicionei as transmissões no meu código, o que não deve afetar o tempo. Aqui está o código do rextester em funcionamento com o resultado: 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 secpara mim localmente. Então, sim, é muito lento ..
Kevin Cruijssen

1

Scala, 774 bytes

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

Não sinto vontade de jogar golfe. Encontra uma solução para o problema colocado dentro de 50ms

O uso pode não ser exatamente o que você deseja:

scala river.scala

Agora você pode inserir continuamente números seguidos de um enter. E encerre o programa com 0. O resultado será impresso assim que você pressionar enter.

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

Eu não sei muito sobre Scala. Então, por favor você pode modificar o código que vai de acordo com rextester.com/l/scala_online_compiler
Kishan Kumar

Tentei colocá-lo lá, mas o tempo limite foi excedido durante a compilação.
AmazingDreams

ok @AmazingDreams
Kishan Kumar

@KishanKumar mesmo o padrão vezes fora de modo que o site parece estar quebrado para scala
AmazingDreams

@KisthanKumar Use este scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b, mas ele não suporta stdin, então tive que mudar algumas coisas menores.
AmazingDreams

1

C, 228283 300 bytes

Este é um mod do código de Yakov para tirar proveito dos padrões do rio. Isso torna ~ 3x mais rápido. Além disso, números inteiros não assinados evitam a cltodpenalidade em máquinas de 64 bits, portanto, são alguns bytes mais longos, mas um pouco mais rápidos.

#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);
        }
    }
}

Explicação:

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

Isso seleciona o rio correto. O rio 1 encontra todos os outros rios, por isso usamos isso como caso de reserva. Se 3 é o maior divisor comum do rio de teste, selecionamos o rio 3 ( 1 + !(i%3)*2). Se 9 é o maior divisor comum do rio de teste, substituímos os valores anteriores e selecionamos o rio 9.

Por que isso funciona? O rio 9 vai 9, 18, 27, 36, etc. Isso dá um múltiplo de 9 a cada vez, portanto, sempre será o caminho mais curto para um rio irmão. O rio 3 passa por um múltiplo de 3 a cada vez: 3, 6, 12, 15, 21, etc. Embora os rios que são múltiplos de 9 também sejam múltiplos de 3, nós os escolhemos como o rio 9 primeiro, deixando apenas o múltiplos de 3. O restante encontrará o rio 1 primeiro: 1, 2, 4, 8, 16, 23, 28, etc.

Depois de selecionarmos o rio correto, pisamos nos dois até que eles se encontrem.


1

Python 3, 144 bytes

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

Muito simples, parece tão longo porque eu desenrolei todos os 3 rios. Primeiro ele gera os 3 rios até RIVER_LENGTH(o que eu espero que seja grande o suficiente) e, em seguida, para cada etapa, Nele faz uma pesquisa binária nos três fluxos para ver se está em algum deles. Isso funciona porque os fluxos já estão classificados, para que possamos fazer o check-in contém o log(n)tempo.

#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:;

    }
}

É preciso um número para o número de casos primeiro, em vez de usar 0para delimitar o final das entradas, porque você sabe, C. Isso é apenas por conveniência e realmente não afeta nada, por isso espero que esteja tudo bem.


Este programa atinge um limite de tempo excedido na ideone de insumos 86,12345,0
Kishan Kumar

ideone.com/mHCeef aqui está o link. E dá uma saída de sinal matar em rextester
Kishan Kumar

@KishanKumar É necessário um número para o número de casos primeiro, em vez de usar 0 para delimitar o final das entradas, porque você sabe, C. Isso é apenas por conveniência e realmente não afeta nada, por isso espero que esteja tudo bem.
Maltysen

@KishanKumar tente este em vez disso: rextester.com/XRJK89444
Maltysen

está certo. Sem problemas. Mas vou ter que escrever um script extra para o seu programa. Como eu tenho que levar o tempo médio de toda a faixa de entrada.
Kishan Kumar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.