Digital River(最短かつ最速のソリューション)


9

これが最初の質問なので、うまくいきますように。

バックグラウンド:

あなたが考えているのは川ではありません。問題は、デジタルリバーの概念に関係しています。デジタルリバーは、次の番号が数字のシーケンスでnあるnその数字のプラス合計。

説明:

1 + 2 + 3 + 4 + 5 = 15であるため、12345の後に12360が続き、12345 + 15は12360になります。同様に、145の後に155が続きます。デジタルリバーの最初の数がの場合、Mこれをriverと呼びますM

たとえば、川480は{480,492,507,519 ....}で始まるシーケンスであり、川483は{483,498,519、....}で始まるシーケンスです。通常の河川と河川は合流することができ、デジタル河川にも同じことが言えます。これは、2つのデジタル河川が同じ値のいくつかを共有している場合に発生します。

例:

480川は519で483川と合流します。480川は507で507川と合流し、481川とは合流しません。すべてのデジタル川は最終的に1川、3川、または9川に合流します。

与えられた整数nに対して、川nがこれら3つの川の1つに最初に出会う場所の値を決定できるプログラムを記述します。

入力

入力には複数のテストケースが含まれる場合があります。各テストケースは個別の行を占め、整数n1 <= n <= 16384)を含みます。0forの値を持つテストケースnは入力を終了し、このテストケースは処理されません。

出力

入力の各テストケースについて、出力例に示すように、最初にテストケース番号(1から開始)を出力します。次に、別の行に「最初にyで川xに出会う」という行を出力します。ここで、yは川がn最初に川に出会う最低値ですx(x = 1または3または9)。の複数の値で川nが川と合流xする場合、最低値を出力します。2つの連続するテストケースの間に空白行を出力します。yx

テストケース

入力:

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 "は2つの理由で意味がありません。最初に、リバーが無限の数列である場合、最後の桁がありません。第二に、次の段落で、川はから始まる川をM意味しMます。
Peter Taylor

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

非ゴルフ:

#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に渡すことができます。数値以外の入力を渡すことで終了できます。

また、30分で打たれたくそ。


現在、テストケースに取り組んでいます。3つの入力テストケースだけはあまり適していません。
Kishan Kumar

stdinからの入力を受け付けます。
Kishan Kumar

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)

非ゴルフおよびテストケース:

ここで試してください。

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)

私はあなたのプログラムを私のものと比較します。私も私の解決策を投稿します。遅い言語を使用する理由。任意の高速言語を使用します。
Kishan Kumar

私は..私はいつも..よっぽどで勝つことはないだろう、ここでのJava 7のコードゴルフの回答を投稿し、後に最速のアルゴリズムタグに気づいたのどちらか短いか、最速とはいえ...ところで、あなたのrextesterはそれだけで警告を与える必要があるときにエラーが発生しますキャストの不足のため/ type-in​​itializes .. ideone(およびEclipse IDE)で動作します。
Kevin Cruijssen、2016年

OK。そうねぇ。rextesterは、コンパイル時間と実行時間を提供します。私はそれを使用して
のKishanクマールを

まあそれはここで問題です。コンパイル時間と実行時間を提供する他のオンラインコンパイラを探します
Kishan Kumar

@KishanKumar私は、私の知る限りここでの時間に影響を与えているべきではない私のコードではキャスト、追加した作業rextesterコード:結果と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私のためにローカルに。ええ、それはかなり遅いです..
ケビンCruijssen

1

Scala、774バイト

フィドル:http : //scalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209b

ゴルフしたくありません。50ms以内に問題の解決策を見つけます

使用法はあなたが望むものとは正確に異なるかもしれません:

scala river.scala

これで、連続して数値を入力して、Enterキーを押すことができます。そして、プログラムを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

Scalaについてはあまり知りません。したがって、rextester.com / l / scala_online_compiler
Kishan Kumar

そこに入れようとしたのですが、コンパイル中にタイムアウトになりました。
AmazingDreams 2016

了解@AmazingDreams
Kishan Kumar

@KishanKumarはデフォルトでもタイムアウトし、サイトがscalaで壊れているようです
AmazingDreams

@KisthanKumarこれを使用しますscalafiddle.net/console/4ec96ef90786e0f2d9f7b61b5ab0209bこれはstdinをサポートしていないため、細かい点をいくつか変更する必要がありました。
AmazingDreams 2016

1

C、228 283 300バイト

これは、川のパターンを利用するためのYakovのコードの改造です。これにより、約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);}}}

非ゴルフ:

#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、6、12、15、21などの3の倍数ごとにステップします。9の倍数である河川 3の倍数ですが、最初に河川9として選択し、 3の倍数。残りは最初に川1に合流します:1、2、4、8、16、23、28など。

正しい川を選択したら、2つの川が合流するまで歩きます。


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

C

非常にシンプルです。3つの川すべてを展開したので、それだけ長く見えます。最初に最大3つの川を生成しますRIVER_LENGTH(十分な大きさであることを願っています)。次に、各ステップでN3つのすべてのストリームに対してバイナリ検索を実行し、いずれかのストリームに含まれているかどうかを確認します。これは、ストリームが既にソートされているので機能し、コンテナーのチェックインを実行できます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で時間制限を超えました
Kishan Kumar

ideone.com/mHCeefこちらがリンクです。そして、それはレキステスターに​​キル信号出力を与えます
Kishan Kumar

@KishanKumar入力の終わりを区切るために0を使用するのではなく、最初にケースの数に数値を使用します。これはCを知っているためです。これは単に便宜上のものであり、実際には何も影響しないので、問題ないことを願っています。
Maltysen、2016年

@KishanKumarは代わりにこれを試してください:rextester.com/XRJK89444
Maltysen

大丈夫です。問題ない。しかし、私はあなたのプログラムのために追加のスクリプトを書かなければなりません。すべての入力範囲の平均時間を取る必要があるので。
Kishan Kumar 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.