Digital River (solution la plus courte et la plus rapide)


9

Ceci est ma première question, donc j'espère que cela se passera bien.

Contexte:

Ce ne sont pas les rivières auxquelles vous pensez. La question tourne autour du concept de rivières numériques. Une rivière numérique est une séquence de nombres où le nombre suivant nest nplus la somme de ses chiffres.

Explication:

12345 est suivi de 12360 puisque 1 + 2 + 3 + 4 + 5 = 15 et donc 12345 + 15 donne 12360. de même 145 est suivi de 155. Si le premier numéro d'une rivière numérique est Mnous l'appellerons rivière M.

Par exemple: River 480 est la séquence commençant {480,492,507,519 ....}, et river 483 est la séquence commençant {483,498,519, ....}. Les ruisseaux et rivières normaux peuvent se rencontrer, et il en va de même pour les rivières numériques. Cela se produit lorsque deux rivières numériques partagent certaines des mêmes valeurs.

Exemple:

La rivière 480 rencontre la rivière 483 à 519. La rivière 480 rencontre la rivière 507 à 507 et ne rencontre jamais la rivière 481. Chaque rivière numérique finira par rencontrer la rivière 1, la rivière 3 ou la rivière 9.

Écrivez un programme qui peut déterminer pour un entier donné nla valeur où la rivière nrencontre d'abord l'une de ces trois rivières.

Contribution

L'entrée peut contenir plusieurs cas de test. Chaque scénario de test occupe une ligne distincte et contient un entier n( 1 <= n <= 16384). Un scénario de test avec la valeur de 0pour ntermine l'entrée et ce scénario de test ne doit pas être traité.

Production

Pour chaque scénario de test dans la première sortie d'entrée, le numéro du scénario de test (à partir de 1), comme indiqué dans l'exemple de sortie. Ensuite, sur une sortie de ligne distincte, la ligne "rencontre d'abord la rivière x en y". Ici, y est la valeur la plus faible où la rivière nrencontre la rivière pour la première fois x(x = 1 ou 3 ou 9). Si la rivière nrencontre la rivière xà yplus d'une valeur de x, émettez la valeur la plus basse. Imprimez une ligne vierge entre deux cas de test consécutifs.

Cas de test

Contribution:

86
12345
0

Production:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

Notation:

L'algorithme le plus rapide gagne. En cas d'égalité. Celui avec un code plus court gagnera.

Merci à mbomb007 d' avoir signalé mon erreur.

ps: Je veux avoir la solution la plus rapide plutôt que la plus petite. J'ai également une de mes solutions qui est lente. Pour cela, regardez ici .

Remarque:

Je vais utiliser ce pour les tests de code. Et la vérification des performances.


3
Je ne suis pas sûr que vous puissiez marquer de cette façon. Que faire si le code de quelqu'un est O (log (log n))? Vous ne pouvez pas tous les couvrir, vous devez donc simplement dire que l'algorithme le plus rapide gagne, mais en cas d'égalité, les gains de code les plus courts et les premières victoires affichées au cas où les deux sont de la même longueur.
mbomb007

3
Je ne trouve rien sur le droit d'auteur ou l'utilisabilité des anciens défis ACM-ICPC, mais je peux trouver ce défi sur le site d'archives. Est-il permis d'utiliser ici?
Geobits du

1
Cela n'a rien à voir avec le droit d'auteur. En cas de doute, le plus simple est normalement d'envoyer un e-mail au (x) propriétaire (s) du site et de lui demander.
Geobits

3
" Si le dernier chiffre d'une rivière numérique est Mnous l'appellerons rivièreM " n'a pas de sens pour deux raisons: premièrement, si une rivière est une séquence infinie de nombres, alors elle n'a pas de dernier chiffre; et deuxièmement, dans le paragraphe suivant, rivièreM signifie la rivière commençant au numéro M.
Peter Taylor

2
D'après la question CR.SE liée, il semble qu'une rivière soit le numéro qui a commencé dans la série, mais voici le dernier chiffre. Qui est correct?
Celeo

Réponses:


3

C, 320 294 octets

Compiler avec -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]);}}

Non golfé:

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

Essaye le!

Essentiellement, les rivières "cibles" sont augmentées jusqu'à ce qu'elles soient plus grandes que la rivière contre laquelle nous testons, puis la rivière test est augmentée. Cette opération est répétée jusqu'à ce que la rivière test soit égale à une autre rivière.

Je ne lis pas les paramètres de la ligne de commande de ce programme et je ne sais pas si vous êtes censé le faire. Vous pouvez maintenant passer des paramètres à STDIN. Vous pouvez terminer en passant une entrée non numérique.

Bon sang, battu d'une demi-heure.


Je travaille sur des cas de test pour l'instant. Seuls 3 cas de test d'entrée ne conviennent pas.
Kishan Kumar

veuillez vous occuper de la saisie de stdin.
Kishan Kumar

3

JavaScript (ES6)

Ceci est une réponse assez rapide en utilisant un langage assez lent. Vraiment, l'exécution du temps ne devrait pas être un problème en utilisant n'importe quelle langue avec des tables de hachage. Tous mes tests sous 100 ms.

Méthode anonyme avec la liste des cas de test comme paramètre d'entrée.

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 octets

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

Oui, c'est long, moche et peut sans aucun doute être complètement changé en code-golf plus .. Je suis à la fois distrait et fatigué, alors je devrais peut-être juste le supprimer à nouveau ..
C'était un défi assez difficile pour être honnête. Mais au moins vous avez votre première réponse ..;) (Ce qui pourrait même être plus long que votre programme C ++ non golfé original .. xD)

Cas non testés et testés:

Essayez-le ici.

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

Production:

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

Je comparerai le vôtre avec le mien. Je vais également publier ma solution. Pourquoi utiliser un langage lent. Utilisez n'importe quel langage rapide.
Kishan Kumar

Je ne remarqué que l'étiquette la plus rapide algorithme plus tard .. Je posterai toujours Java 7 réponses code de golf ici .. Il est defintely ne va pas gagner soit le plus court ou le plus rapide mais .. BTW, votre rextester donne des erreurs quand il ne devrait donner des avertissements par manque de transtypages / type-initialise .. Il fonctionne sur ideone (et dans Eclipse IDE).
Kevin Cruijssen

D'accord. laisse moi voir. rextester donne le temps de compilation et le temps d'exécution. Je l'ai donc utilisé
Kishan Kumar

c'est un problème ici. Je vais chercher un autre compilateur en ligne qui donne le temps de compilation et le temps d'exécution
Kishan Kumar

@KishanKumar J'ai ajouté les transtypages dans mon code, ce qui ne devrait pas affecter le temps afaik Voici le code de rextester fonctionnel avec le résultat: 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 secpour moi localement. Alors oui, c'est assez lent ..
Kevin Cruijssen

1

Scala, 774 octets

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

Je n'ai pas envie de jouer au golf. Il trouve une solution au problème posé dans les 50 ms

L'utilisation peut ne pas être exactement ce que vous voulez:

scala river.scala

Vous pouvez maintenant saisir en continu des nombres suivis d'une entrée. Et terminez le programme avec 0. Le résultat sera imprimé dès que vous appuyez sur Entrée.

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

Je ne connais pas grand-chose à Scala. Alors, s'il vous plaît, pourriez-vous modifier le code qui, selon rextester.com/l/scala_online_compiler
Kishan Kumar

J'ai essayé de le mettre là-dedans mais il a expiré pendant la compilation.
AmazingDreams

ok @AmazingDreams
Kishan Kumar

@KishanKumar même la valeur par défaut expire, donc le site semble être cassé pour scala
AmazingDreams

@KisthanKumar Utilisez celui-ci scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b mais il ne prend pas en charge stdin, j'ai donc dû changer quelques petites choses.
AmazingDreams

1

C, 228 283 300 octets

Ceci est un mod du code de Yakov pour profiter des modèles de rivière. Cela le rend environ 3 fois plus rapide. De plus, les entiers non signés évitent la cltodpénalité sur les machines 64 bits, c'est donc quelques octets de plus mais fractionnellement plus rapide.

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

Non golfé:

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

Explication:

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

Cela sélectionne la bonne rivière. La rivière 1 rencontre toutes les autres rivières, nous utilisons donc cela comme cas de repli. Si 3 est le plus grand diviseur commun de la rivière test, nous sélectionnons la rivière 3 ( 1 + !(i%3)*2). Si 9 est le plus grand diviseur commun de la rivière test, nous remplaçons les valeurs précédentes et sélectionnons la rivière 9.

Pourquoi ça marche? La rivière 9 passe à 9, 18, 27, 36, etc. Cela fait un multiple de 9 à chaque fois, donc ce sera toujours le chemin le plus court vers une rivière sœur. La rivière 3 progressera par un multiple de 3 à chaque fois: 3, 6, 12, 15, 21, etc. Alors que les rivières qui sont un multiple de 9 sont également un multiple de 3, nous les choisissons comme rivière 9 en premier, ne laissant que le multiples de 3. Le reste rencontrera la rivière 1 en premier: 1, 2, 4, 8, 16, 23, 28, etc.

Une fois que nous avons sélectionné notre bonne rivière, nous marchons les deux rivières jusqu'à ce qu'elles se rencontrent.


1

Python 3, 144 octets

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

Très simple, ça a l'air si long car j'ai déroulé les 3 rivières. Il génère d'abord les 3 rivières jusqu'à RIVER_LENGTH(ce qui, je l'espère, est assez grand), puis pour chaque étape, Nil effectue une recherche binaire sur les trois flux pour voir s'il se trouve dans l'un d'eux. Cela fonctionne parce que les flux sont déjà triés, nous pouvons donc faire le check-in de log(n)temps.

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

    }
}

Il faut d'abord un nombre pour le nombre de cas, au lieu d'utiliser 0pour délimiter la fin des entrées, parce que vous savez, C. C'est juste pour plus de commodité et n'affecte vraiment rien, donc j'espère que ça va.


Ce programme atteint une limite de temps dépassée sur ideone sur les entrées 86,12345,0
Kishan Kumar

ideone.com/mHCeef voici le lien. Et il donne une sortie de signal kill sur rextester
Kishan Kumar

@KishanKumar Il faut d'abord un nombre pour le nombre de cas, au lieu d'utiliser 0 pour délimiter la fin des entrées, parce que vous savez, C. C'est juste pour plus de commodité et n'affecte vraiment rien, donc j'espère que ça va.
Maltysen

@KishanKumar essayez celui-ci à la place: rextester.com/XRJK89444
Maltysen

c'est bon. Aucun problème. Mais je devrai écrire un script supplémentaire pour votre programme. Comme je dois prendre le temps moyen de toute la plage d'entrée.
Kishan Kumar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.