合計が121212になるすべての数値ペアを検索します[完了]


8

この問題はブルートフォースで簡単に実行できます。実際、ブルートフォースにもかなり速くなります。しかし、その中でどこが楽しいのでしょうか。

問題

合計がになるすべての一意の5桁の数値ペアのリストを作成し121212ます。ただし、各10進数字は、どちらかの数値で1回だけ使用する必要があります。したがって、有効なペアはになります(98167, 23045)。しかし、無効なペアは次のようになります(23456, 97756)ので、7, 5, 6複数回繰り返され、1, 8, 0一切使用しておりません。正確に192の一意のペアがあります。

ルール

  1. 効率:これを総当たりにすることができます。しかし、それは簡単なことです。したがって、代わりに、ここでの実際の課題は、数値のリストを効率的に生成する方法を見つけることです。

  2. ソースコード要件:番号リスト(またはその一部)を保存できません。番号シーケンスはオンザフライで生成する必要あります。

楽しんで!


1
「10塁想定」と言っていた箇所を見逃しましたか?;)
kojiro

1
@kojiro:指はいくつありますか?:-)
mellamokb

1
@kojiro:いいえ。それが機能する他の拠点を見つけることができれば、ぜひ...それは素晴らしいことだと思います!
ircmaxell

@kojiroの種類:「10進数字が表示される必要があります...」5桁の16進数がAFを含まない限り2つ見つけることができるようです
Cephalopod

@mellamokb 10本の指ですが、20桁あります。
小次郎2014年

回答:


6

JavaScript

function findpairs(arrin1,arrin2){
    functioncount++
    var arr1=[]
    var arr2=[]
    var strike=[]
    var overflow=0
    var b
    var len=arrin1.length
    for(var a=0;a<len;a++){
        arr1[a]=arrin1[a]
        arr2[a]=arrin2[a]
        strike[arr1[a]]=true
        strike[arr2[a]]=true
        overflow=+((arr1[a]+arr2[a])>9)
    }
    var desired=12-(len%2)-overflow
    for(a=9;a>0;a--){
        b=(desired-a)%10
        if(a>b && !strike[a] && !strike[b]){
            if(len==4){
                if((a+b)>9){
                    document.write(""+a+arr1[3]+arr1[2]+arr1[1]+arr1[0]+" "+b+arr2[3]+arr2[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr1[1]+arr2[0]+" "+b+arr2[3]+arr2[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr2[1]+arr1[0]+" "+b+arr2[3]+arr2[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr1[2]+arr2[1]+arr2[0]+" "+b+arr2[3]+arr2[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr1[1]+arr1[0]+" "+b+arr2[3]+arr1[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr1[1]+arr2[0]+" "+b+arr2[3]+arr1[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr2[1]+arr1[0]+" "+b+arr2[3]+arr1[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr1[3]+arr2[2]+arr2[1]+arr2[0]+" "+b+arr2[3]+arr1[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr1[1]+arr1[0]+" "+b+arr1[3]+arr2[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr1[1]+arr2[0]+" "+b+arr1[3]+arr2[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr2[1]+arr1[0]+" "+b+arr1[3]+arr2[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr1[2]+arr2[1]+arr2[0]+" "+b+arr1[3]+arr2[2]+arr1[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr1[1]+arr1[0]+" "+b+arr1[3]+arr1[2]+arr2[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr1[1]+arr2[0]+" "+b+arr1[3]+arr1[2]+arr2[1]+arr1[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr2[1]+arr1[0]+" "+b+arr1[3]+arr1[2]+arr1[1]+arr2[0]+"<br>")
                    document.write(""+a+arr2[3]+arr2[2]+arr2[1]+arr2[0]+" "+b+arr1[3]+arr1[2]+arr1[1]+arr1[0]+"<br>")
                    resultcount+=16
                }
            }
            else{
                arr1[len]=a
                arr2[len]=b
                findpairs(arr1,arr2)
            }
        }
    }
}
resultcount=0
functioncount=0
start=+new Date()
findpairs([],[])
end=+new Date()
document.write("<br>"+resultcount+" results<br>"+(end-start)+" ms<br>"+functioncount+" function calls")

ホスティング先:http : //ebusiness.hopto.org/findpairs.htm

数学的実現:1つのペアがある場合、2つの数値間で数字を交換することで15個の他のペアを簡単に生成できるため、最初の数字がすべて2番目の数字より大きい数字のみを検索し、単純にすべてを出力します順列。

最下位の数字から始め、シーケンスをツリートラバーサルとして生成します。各ステップで、中間結果が正しく、数字が2回費やされていないことを主張します。これらのメソッドを使用すると、関数は合計で50回呼び出すだけで済みます。私のマシンでは、Chromeのランタイム結果は通常2ミリ秒です。


8

C ++

#include<iostream>
using namespace std;
#include<algorithm>

int main()
{
    long long N,F,S;
    char str[11]="1023456789";
    while (1) {
        sscanf(str,"%lld",&N);
        F=N/100000;S=N%100000;
        if (F>60000)
           break;
        if (F+S==121212)
           printf("%lld %lld\n",F,S);
        next_permutation(str,str+10);
    }
}

http://www.ideone.com/Lr84g


2
とても興味深い。つまり、上部が60001未満(約1,768,168回の反復、または少し少し10!/2)の可能なすべての順列を反復処理し、それが121212に合計可能かどうかを確認します。最初の実行ではまったく問題ありません。しかし、もっと効率的になるかどうか私はまだ興味があります...
ircmaxell

番号リストを保存することは許可されていないと思いました...あいまいな表現ですか?
bltxd 2011年

@bltxd:事前に保存するつもりでした。生成時に保存できます。しかし(51430, 69872)、それを有効なペアとして保存することはできません。数字リスト(0123456789)と合計(121212)を事前に保存できます。
ircmaxell 2011年

それが最も効率的な方法ではないことに同意しますが、それが異なることを願っています。
fR0DDY 2011年

4

Python 2。

数字を構成するのでかなり効率的です(最も内側のループは合計4570回実行されます)。少し(201文字)ゴルフしたのでかなり短いですが、これについて説明したいのか本当にわかりません:)

p=lambda t,a,d:((x,y)for x in range(10)for y in[(t-x-a)%10]if(x not in d)&(y not in d)and x-y)
w=lambda s:[s]if len(s)==10and s[:5]<s[5:]else(m for n in p(2-len(s)/2%2,sum(s[-2:])/10,s)for m in w(s+n))

ただし、返される値はかなり独特です。w空のタプルを指定して呼び出すと、10タプルのイテレータが作成されます。これら10組は、残念ながらの二つの数字の桁である後方交互すなわちタプル

(2, 0, 8, 3, 7, 4, 9, 1, 6, 5)

数値51430および69782を表します。

テスト:

result = list(w(()))

assert len(set(result)) == 192               # found all values
assert len(result) == 192                    # and no dupes 

for digits in result:
    assert all(0 <= d <= 9 for d in digits)  # real digits -- zero through nine
    assert len(set(digits)) == 10            # all digits distinct

    n1 = int("".join(map(str, digits[9::-2])))
    n2 = int("".join(map(str, digits[8::-2])))

    assert n1 + n2 == 121212                 # sum is correct

これはゴルフされていないバージョンです:

ppcalls = 0       # number of calls to possiblePairs
ppyields = 0      # number of pairs yielded by possiblePairs
ppconstructed = 0 # number of construced pairs; this is the number
                  #     of times we enter the innermost loop

def possiblePairs(theirSumMod10, addition, disallowed):
    global ppcalls, ppyields, ppconstructed
    ppcalls += 1
    for a in range(10):
        b = (theirSumMod10 - a - addition) % 10
        ppconstructed += 1
        if a not in disallowed and b not in disallowed and a != b:
            ppyields += 1
            yield (a, b)

def go(sofar):
    if len(sofar) == 10:
        if sofar[:5] < sofar[5:]: # dedupe
            yield sofar

    digitsum = 2 - (len(sofar) / 2) % 2 # 1 or 2, alternating

    for newpair in possiblePairs(digitsum, sum(sofar[-2:]) / 10, sofar):
        for more in go(sofar + newpair):
            yield more


list(go(()))        # iterate

print ppcalls       # 457
print ppyields      # 840
print ppconstructed # 4570

3

C

#include <stdio.h>

int mask(int n)
{
    int ret = 0;

    for (; n > 0; n /= 10)
        ret |= 1 << n % 10;

    return ret;
}

int main(void)
{
    int a, b;

    for (a = 21213, b = 99999; a < b; a++, b--)
        if ((mask(a) | mask(b)) == 0x3FF)
            printf("%d %d\n", a, b);

    return 0;
}

これは、合計が121212になる5桁の数値のすべてのペアをトラバースします(つまり、39393回の反復、つまりfR0DDYの回答で使用される反復の〜1 /46 )。各ペアについて、各数値の数字のビットマスクを形成し、ORが0b1111111111にORであるかどうかを確認します。


毎回マスクの10回の反復を追加すると、時間の複雑さは私の場合よりも1/5倍だけ良くなります。:)
fR0DDY

2

JavaScript(481)

function m(d,i){o=d-i;if(0<=o&&o<=9&&o!=i)return o;o+=10;if(0<=o&&o<=9&&o!=i)return o;return}function p(n,a){x=0;r=[];d=n%10;for(i=0;i<10;i++){if((!a||!a.contains(i))&&(o=m(d,i))&&(!a||!a.contains(o))&&i+o<=n)r[x++]=[i,o]}return r}function f(n,a){var x=0;var r=[];var d=p(n,a);for(var i=0;i<d.length;i++){var s=Math.floor((n-d[i][0]-d[i][1])/10);if(s>0){var t=f(s,d[i].concat(a));for(var j=0;j<t.length;j++)r[x++]=[t[j][0]*10+d[i][0],t[j][1]*10+d[i][1]]}else{r[x++]=d[i]}}return r}

http://jsfiddle.net/XAYr3/4/

基本的な考え方:右端の列で使用できる有効な数字の組み合わせを生成します。たとえば、(0,2)、(3,9)、(4,8)、(5,7)。組み合わせごとに、最初のペアの数字を複製せずに、右から1番目の数字で機能するペアを再帰的に見つけます。5桁の数字のペアが生成されるまで再帰します。これらすべての結果を1つの配列に結合します。リストは192要素です。これは、必要な反復回数が最も少ないはずだと思いますが、すべての配列の割り当て/割り当て解除により、全体的にやや非効率的になります。

私のカウントテストでは、関数fが310回呼び出され、内部ループiが(すべての呼び出しに対してf)合計501回実行され、内部-内部ループjが(すべてに対して)合計768回実行されることが示されています。


1

Python、171文字

def R(x,y,d,c):
 if not d and x<y:print x,y
 for p in d:
  q=(12-c%2-p-(x+y)/10**c)%10
  if p-q and q in d:R(x+p*10**c,y+q*10**c,d-set([p,q]),c+1)
R(0,0,set(range(10)),0)

コードはという不変維持しxy持っているc数字を、すべての未使用の桁がセットになっていることd

このルーチンRは合計841回呼び出され、かなり効率的です。


0

C ++

#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>

int main()
{
        int i;
        char str1[11]="0123456789",str2[11];
        for (i=99999;i>60000;i--)
        {
                sprintf(str2,"%d%d",i,121212-i);
                sort(str2,str2+10);
                if(!strcmp(str1,str2))
                        printf("%d %d\n",i,121212-i);
        }
}

http://www.ideone.com/Lr84g

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.