Sungai Digital (Solusi Terpendek Dan Tercepat)


9

Ini adalah pertanyaan pertama saya, jadi saya harap ini berjalan dengan baik.

Latar Belakang:

Bukan sungai yang mungkin Anda pikirkan. Pertanyaannya berkisar pada konsep sungai digital. Sebuah sungai digital adalah urutan angka dimana jumlah berikut nadalah nditambah jumlah digit.

Penjelasan:

12345 diikuti oleh 12360 karena 1 + 2 + 3 + 4 + 5 = 15 dan 12345 + 15 menghasilkan 12360. demikian pula 145 diikuti oleh 155. Jika angka pertama dari sungai digital adalah Mkita akan menyebutnya sungai M.

Sebagai contoh: Sungai 480 adalah urutan awal {480,492,507,519 ....}, dan sungai 483 adalah urutan awal {483,498,519, ....}. Sungai dan sungai normal dapat bertemu, dan hal yang sama berlaku untuk sungai digital. Ini terjadi ketika dua sungai digital berbagi beberapa nilai yang sama.

Contoh:

Sungai 480 memenuhi sungai 483 di 519. Sungai 480 bertemu sungai 507 di 507 dan tidak pernah bertemu sungai 481. Setiap sungai digital akhirnya akan bertemu sungai 1, sungai 3 atau sungai 9.

Tulis sebuah program yang dapat menentukan untuk bilangan bulat tertentu nnilai di mana sungai npertama kali bertemu satu dari tiga sungai ini.

Memasukkan

Input mungkin berisi beberapa test case. Setiap test case menempati baris terpisah dan berisi integer n( 1 <= n <= 16384). Kasing uji dengan nilai 0untuk nmengakhiri input dan kasing uji ini tidak boleh diproses.

Keluaran

Untuk setiap test case di input pertama output jumlah case test (mulai dari 1) seperti yang ditunjukkan dalam output sampel. Kemudian pada baris yang terpisah menghasilkan garis "pertama kali bertemu sungai x at y". Di sini y adalah nilai terendah di mana sungai npertama kali bertemu sungai x(x = 1 atau 3 atau 9). Jika sungai nmemenuhi sungai xdengan ynilai lebih dari satu x, hasilkan nilai terendah. Cetak garis kosong antara dua kotak uji berurutan.

Kasus cobaan

Memasukkan:

86
12345
0

Keluaran:

Case #1

first meets river 1 at 101

Case #2

first meets river 3 at 12423

Mencetak:

Algoritma tercepat menang. Dalam hal dasi. Yang dengan kode pendek akan menang.

Terima kasih kepada mbomb007 karena menunjukkan kesalahan saya.

ps: Saya ingin memiliki solusi tercepat daripada yang terkecil. Saya juga punya solusi yang lambat. Untuk itu lihat di sini .

catatan:

Saya akan menggunakan ini untuk pengujian kode. Dan pengecekan kinerja.


3
Saya tidak yakin Anda bisa mencetak gol seperti itu. Bagaimana jika kode seseorang adalah O (log (log n))? Anda tidak dapat membahas semuanya, jadi Anda hanya perlu mengatakan bahwa algoritma tercepat menang, tetapi dalam kasus seri, kode terpendek menang, dan kemenangan pertama yang diposkan jika keduanya panjangnya sama.
mbomb007

3
Saya tidak dapat menemukan apa pun tentang hak cipta atau kegunaan tantangan ACM-ICPC lama, tetapi saya dapat menemukan tantangan ini di situs arsip. Apakah boleh menggunakan di sini?
Geobits

1
Itu tidak ada hubungannya dengan hak cipta. Jika ragu, hal yang paling mudah adalah mengirimkan surel kepada pemilik situs dan bertanya.
Geobits

3
" Jika digit terakhir dari sebuah sungai digital adalah Mkita akan menyebutnya sungaiM " tidak masuk akal karena dua alasan: pertama, jika sungai adalah urutan angka yang tak terbatas maka ia tidak memiliki digit terakhir; dan kedua, pada paragraf sungaiM berikutnya berarti sungai dimulai dari angka M.
Peter Taylor

2
Dari pertanyaan CR.SE yang ditautkan, sepertinya sungai adalah nomor yang dimulai dengan seri, tapi ini dia digit terakhir. Yang mana yang benar?
Celeo

Jawaban:


3

C, 320 294 byte

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

Tidak Disatukan:

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

Cobalah!

Pada dasarnya, sungai "target" meningkat hingga lebih besar dari sungai yang kami uji melawan, dan setelah itu sungai uji ditingkatkan. Ini diulangi sampai sungai uji sama dengan beberapa sungai lain.

Saya tidak membaca parameter dari baris perintah di program ini, dan saya tidak yakin apakah Anda seharusnya. Sekarang Anda dapat meneruskan parameter ke STDIN. Anda dapat mengakhiri dengan mengirimkan input non-numerik.

Sial, dipukuli setengah jam.


Saya sedang mengerjakan kasus uji untuk saat ini. Hanya 3 input test case yang tidak cocok.
Kishan Kumar

maukah Anda mengambil input dari stdin.
Kishan Kumar

3

JavaScript (ES6)

Ini adalah jawaban yang cukup cepat menggunakan bahasa yang cukup lambat. Sungguh, waktu eksekusi seharusnya tidak menjadi masalah menggunakan bahasa apa pun dengan tabel hash. Semua pengujian saya di bawah 100 ms.

Metode anonim dengan daftar kasus uji sebagai parameter 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;}

Ya, ini panjang, jelek, dan tanpa diragukan lagi dapat sepenuhnya diubah menjadi kode-golf lebih. Saya berdua terganggu dan lelah, jadi mungkin saya harus menghapusnya lagi ..
Itu adalah tantangan yang cukup sulit untuk jujur. Tapi setidaknya Anda memiliki jawaban pertama Anda ..;) (Yang mungkin bahkan lebih lama dari program C ++ asli yang tidak di-ungolfed Anda .. xD)

Kasus yang tidak disatukan & uji:

Coba di sini.

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

Keluaran:

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

Saya akan membandingkan program Anda dengan program saya. Saya juga akan memposting solusi saya juga. Mengapa menggunakan bahasa yang lambat. Gunakan bahasa cepat apa pun.
Kishan Kumar

Saya hanya memperhatikan tag algoritme tercepat di kemudian hari. Saya selalu memposting jawaban kode-Java 7 di sini .. Pasti tidak akan menang dalam waktu tersingkat atau tercepat sekalipun. Btw, rextester Anda memberikan kesalahan padahal seharusnya hanya memberikan peringatan karena kekurangan gips / ketik-menginisialisasi .. Ini berfungsi pada ideone (dan di Eclipse IDE).
Kevin Cruijssen

baik. izinkan aku melihat. rextester memberikan waktu kompilasi dan waktu eksekusi. Jadi saya menggunakannya
Kishan Kumar

nah itu masalah di sini. Saya akan mencari kompiler online lainnya yang memberikan waktu kompilasi dan waktu eksekusi
Kishan Kumar

@KishanKumar Saya telah menambahkan gips dalam kode saya, yang seharusnya tidak mempengaruhi waktu afaik Berikut adalah kode rextester yang berfungsi dengan hasilnya: 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 secuntuk saya secara lokal. Jadi ya, ini sangat lambat ..
Kevin Cruijssen

1

Scala, 774 byte

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

Saya tidak ingin bermain golf. Itu menemukan solusi untuk masalah yang diajukan dalam 50ms

Penggunaan mungkin tidak persis seperti yang Anda inginkan:

scala river.scala

Sekarang Anda dapat secara terus-menerus memasukkan angka yang diikuti oleh sebuah entri. Dan hentikan program dengan 0. Hasilnya akan dicetak segera setelah Anda menekan 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

Saya tidak tahu banyak tentang Scala. Jadi tolong Anda dapat memodifikasi kode yang sesuai dengan rextester.com/l/scala_online_compiler
Kishan Kumar

Saya mencoba untuk meletakkannya di sana tetapi waktunya habis saat mengkompilasi.
AmazingDreams

ok @AmazingDreams
Kishan Kumar

@KishanKumar bahkan default satu kali keluar sehingga situs tersebut tampaknya rusak untuk scala
AmazingDreams

@KisthanKumar Gunakan ini scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b tidak mendukung stdin, jadi saya harus mengubah beberapa hal kecil.
AmazingDreams

1

C, 228 283 300 byte

Ini adalah mod dari kode Yakov untuk mengambil keuntungan dari pola sungai. Ini membuatnya ~ 3x lebih cepat. Juga, bilangan bulat yang tidak ditandatangani menghindari cltodpenalti pada mesin 64-bit, jadi itu beberapa byte lebih lama tetapi lebih cepat.

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

Tidak Disatukan:

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

Penjelasan:

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

Ini memilih sungai yang benar. Sungai 1 bertemu setiap sungai lainnya, jadi kami menggunakan ini sebagai kasing mundur. Jika 3 adalah pembagi umum terbesar dari sungai uji, kami memilih sungai 3 ( 1 + !(i%3)*2). Jika 9 adalah pembagi umum terbesar dari sungai uji, kami menimpa nilai sebelumnya dan memilih sungai 9.

Mengapa ini bekerja? Sungai 9 pergi 9, 18, 27, 36, dll. Ini langkah dengan kelipatan 9 setiap kali sehingga akan selalu menjadi rute terpendek ke sungai saudara. Sungai 3 akan melangkah dengan kelipatan 3 setiap kali: 3, 6, 12, 15, 21, dll. Sementara sungai yang kelipatan 9 juga kelipatan 3, kami memilihnya sebagai sungai 9 terlebih dahulu, hanya menyisakan kelipatan 3. Sisanya akan bertemu sungai 1 pertama: 1, 2, 4, 8, 16, 23, 28, dll.

Setelah kami memilih sungai yang benar, kami melangkah dua sungai sampai mereka bertemu.


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

Sangat sederhana, itu hanya terlihat lama karena saya membuka gulungan semua 3 sungai. Pertama-tama menghasilkan 3 sungai hingga RIVER_LENGTH(yang saya harap cukup besar), dan kemudian untuk setiap langkah di Natasnya melakukan pencarian biner pada ketiga aliran untuk melihat apakah ada di salah satu dari mereka. Ini berfungsi karena stream sudah diurutkan, sehingga kita dapat melakukan check-in berisi log(n)waktu.

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

    }
}

Dibutuhkan nomor untuk jumlah kasus terlebih dahulu, daripada menggunakan 0untuk membatasi akhir input, karena Anda tahu, C. Ini hanya untuk kenyamanan dan tidak benar-benar mempengaruhi apa pun, jadi saya harap tidak apa-apa.


Program ini mencapai batas waktu terlampaui pada ideone pada input 86.12345,0
Kishan Kumar

ideone.com/mHCeef di sini adalah tautannya. Dan itu memberikan output sinyal mematikan pada rextester
Kishan Kumar

@KishanKumar Dibutuhkan nomor untuk jumlah kasus terlebih dahulu, daripada menggunakan 0 untuk membatasi akhir input, karena Anda tahu, C. Ini hanya untuk kenyamanan dan tidak benar-benar mempengaruhi apa pun, jadi saya harap tidak apa-apa.
Maltysen

@KishanKumar coba yang ini sebagai gantinya: rextester.com/XRJK89444
Maltysen

tidak apa-apa. Tidak masalah. Tetapi saya harus menulis skrip tambahan untuk program Anda. Karena saya harus mengambil waktu rata-rata dari semua rentang input.
Kishan Kumar
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.