Digital River (самое короткое и быстрое решение)


9

Это мой первый вопрос, поэтому я надеюсь, что он пройдет хорошо.

Фон:

Вы можете думать не о реках. Вопрос вращается вокруг концепции цифровых рек. Цифровая река представляет собой последовательность чисел , где число следующее nв nплюс сумма его цифр.

Объяснение:

За 12345 следует 12360, так как 1 + 2 + 3 + 4 + 5 = 15 и, следовательно, 12345 + 15 дает 12360. Точно так же за 145 следует 155. Если первое число цифровой реки - это Mмы будем называть ее рекой M.

Например, река 480 - это начало последовательности {480,492,507,519 ....}, а река 483 - начало последовательности {483,498,519, ....}. Нормальные ручьи и реки могут встречаться, и то же самое верно для цифровых рек. Это происходит, когда две цифровые реки имеют одни и те же значения.

Пример:

Река 480 встречается с рекой 483 в точке 519. Река 480 встречается с рекой 507 в точке 507 и никогда не встречается с рекой 481. Каждая цифровая река в конечном итоге встретится с рекой 1, рекой 3 или рекой 9.

Напишите программу, которая может определить для данного целого числа nзначение, в котором река nвпервые встречается с одной из этих трех рек.

вход

Входные данные могут содержать несколько тестовых случаев. Каждый тестовый пример занимает отдельную строку и содержит целое число n( 1 <= n <= 16384). Тестовый случай со значением 0for nзавершает ввод, и этот тестовый случай не должен обрабатываться.

Вывод

Для каждого теста на входе сначала выведите номер теста (начиная с 1), как показано в примере вывода. Затем в отдельной строке выведите строку «сначала встречается река x в точке y». Здесь у - самое низкое значение, при котором река nвпервые встречается с рекой x(х = 1, 3 или 9). Если река nвстречает реку xв yтечение более чем одного значения x, выходное самое низкое значение. Выведите пустую строку между двумя последовательными тестами.

Прецедент

Входные данные:

86
12345
0

Вывод:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

Подсчет очков:

Самый быстрый алгоритм выигрывает. В случае галстука. Победит тот, у кого более короткий код.

Спасибо mbomb007 за указание на мою ошибку.

PS: Я хочу иметь самое быстрое решение, а не самое маленькое. У меня также есть мое решение, которое медленно. Для этого посмотрите здесь .

Замечания:

Я буду использовать это для тестирования кода. И проверка работоспособности.


3
Я не уверен, что вы можете забить таким образом. Что если чей-то код O (log (log n))? Вы не можете охватить их все, поэтому вам просто нужно сказать, что выигрывает самый быстрый алгоритм, но в случае связывания выигрывает самый короткий код и первые опубликованные выигрыши, если оба имеют одинаковую длину.
mbomb007

3
Я не могу найти что-либо об авторском праве или удобстве использования старых задач ACM-ICPC, но я могу найти эту проблему на сайте архива. Допустимо ли здесь использовать?
Geobits

1
Это не имеет ничего общего с авторским правом. Если есть сомнения, обычно проще всего написать письмо владельцу (-ам) сайта и спросить.
Geobits

3
« Если последняя цифра цифровой реки - Mмы будем называть ее рекойM », то это не имеет смысла по двум причинам: во-первых, если река представляет собой бесконечную последовательность чисел, то у нее нет последней цифры; и во-вторых, в следующем абзаце рекаM означает реку, начинающуюся с номера M.
Питер Тейлор,

2
Из связанного вопроса CR.SE кажется, что река - это то число, с которого начинаются серии, но вот последняя цифра. Что правильно?
Celeo

Ответы:


3

C 320 294 байта

Компилировать с -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]);
    }
}

Попробуйте!

По сути, «целевые» реки увеличиваются до тех пор, пока они не станут больше, чем река, с которой мы тестируем, и после этого тестовая река будет увеличена. Это повторяется до тех пор, пока тестовая река не станет равной какой-либо другой реке.

Я не читаю параметры из командной строки в этой программе, и я не уверен, если вы должны. Теперь вы можете передавать параметры в STDIN. Вы можете завершить, передав нечисловой ввод.

Тоже штопать, бить на полчаса.


Я сейчас работаю над тестовыми примерами. Только 3 входных теста не будут подходящими.
Кишан Кумар

Пожалуйста, не могли бы вы принять участие от stdin.
Кишан Кумар

3

JavaScript (ES6)

Это довольно быстрый ответ, использующий довольно медленный язык. Действительно, выполнение времени не должно быть проблемой при использовании любого языка с хеш-таблицами. Все мои тесты под 100 мс.

Анонимный метод со списком тестов в качестве входного параметра.

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 байт

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

Да, это долго, безобразно и, без сомнения, может быть полностью изменено на код-гольф это больше ... Я и отвлечен, и устал, так что, возможно, я должен просто удалить это снова.
Это был довольно сложный вызов, если честно. . Но, по крайней мере, у вас есть ваш первый ответ ..;) (который может быть даже длиннее, чем ваша оригинальная программа на C ++ без гольфа .. xD)

Ungolfed и тестовые случаи:

Попробуй это здесь.

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

Вывод:

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

Я сравню вашу программу с моей. Я также собираюсь опубликовать свое решение тоже. Зачем использовать медленный язык. Используйте любой быстрый язык.
Кишан Кумар

Позже я заметил только тэг самого быстрого алгоритма. Я всегда публикую здесь ответы о коде в Java 7. Он определенно не выиграет ни в самом коротком , ни в самом быстром ходе ... Кстати, ваш рецензент выдает ошибки, когда должен только предупреждать из-за отсутствия приведения / инициализации типа. Работает на ideone (и в Eclipse IDE).
Кевин Круйссен

Хорошо. дайте-ка подумать. rextester дает время компиляции и время выполнения. Так что я использовал это
Кишан Кумар

хорошо вот проблема здесь. Я поищу другой онлайн-компилятор, который дает время компиляции и время выполнения
Кишан Кумар

@KishanKumar Я добавил приведение в мой код, который не должен влиять на время. Вот рабочий код реэкстестера с результатом: 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 secдля меня локально. Так что да, это довольно медленно ..
Кевин Круйссен

1

Scala, 774 байта

Скрипка: http://scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b

Мне не хочется играть в гольф. Он находит решение поставленной проблемы в течение 50 мс

Использование может быть не совсем то, что вы хотите:

scala river.scala

Теперь вы можете непрерывно вводить числа с последующим вводом. И завершите программу с 0. Результат будет напечатан, как только вы нажмете 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

Я не знаю много о Скала. Поэтому, пожалуйста, не могли бы вы изменить код, который будет в соответствии с rextester.com/l/scala_online_compiler
Кишан Кумар

Я попытался поместить это там, но это истекло во время компиляции.
AmazingDreams

хорошо @AmazingDreams
Кишан Кумар

@KishanKumar даже по умолчанию один раз, поэтому сайт, кажется, не работает для scala
AmazingDreams

@KisthanKumar Используйте этот scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b, но он не поддерживает stdin, поэтому мне пришлось изменить некоторые мелочи.
AmazingDreams

1

C 228 283 300 байт

Это мод кода Якова, чтобы использовать преимущества речных паттернов. Это делает это в 3 раза быстрее. Кроме того, целые числа без знака избегают cltodштрафов на 64-битных машинах, поэтому они на несколько байтов длиннее, но незначительно быстрее.

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

Объяснение:

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

Это выбирает правильную реку. Река 1 встречается с любой другой рекой, поэтому мы используем это как запасной вариант. Если 3 - наибольший общий делитель тестовой реки, мы выбираем реку 3 ( 1 + !(i%3)*2). Если 9 - наибольший общий делитель тестовой реки, мы переопределяем предыдущие значения и выбираем реку 9.

Почему это работает? Река 9 идет 9, 18, 27, 36 и т. Д. Это число, кратное 9, каждый раз, таким образом, это всегда будет кратчайший путь к сестринской реке. Река 3 будет умножаться на 3 каждый раз: 3, 6, 12, 15, 21 и т. Д. Хотя реки, кратные 9, также кратны 3, сначала мы выбираем их в качестве реки 9, оставляя только кратно 3. Остальная часть сначала встретит реку 1: 1, 2, 4, 8, 16, 23, 28 и т. д.

Как только мы выбрали правильную реку, мы переходим две реки, пока они не встретятся.


1

Python 3, 144 байта

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

С

Очень просто, это выглядит так долго, потому что я развернул все 3 реки. Сначала он генерирует 3 реки до RIVER_LENGTH(что, я надеюсь, достаточно велико), а затем для каждого шага Nвыполняет двоичный поиск по всем трем потокам, чтобы определить, находится ли он в каком-либо из них. Это работает, потому что потоки уже отсортированы, поэтому мы можем выполнить проверку содержимого 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:;

    }
}

Сначала нужно число для числа дел, вместо того, чтобы использовать 0для разделения конца входных данных, потому что вы знаете, C. Это просто для удобства и на самом деле ни на что не влияет, поэтому я надеюсь, что все в порядке.


Эта программа превысила ограничение по времени для идеона на входах 86,12345,0
Кишан Кумар

ideone.com/mHCeef вот ссылка. И это дает выходной сигнал выхода на rextester
Кишан Кумар

@KishanKumar Сначала нужно число для числа дел, вместо того, чтобы использовать 0 для разграничения конца входных данных, потому что вы знаете, C. Это просто для удобства и на самом деле ни на что не влияет, поэтому я надеюсь, что все в порядке.
Maltysen

@KishanKumar попробуйте этот вариант
Maltysen

все нормально. Нет проблем. Но мне придется написать дополнительный скрипт для вашей программы. Поскольку я должен взять среднее время всего входного диапазона.
Кишан Кумар
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.