マッチスティック方程式


16

この課題におけるあなたの仕事は、このような「マッチスティック方程式」を分析することです...

ここに画像の説明を入力してください

...そして、一致を再配置することで有効な方程式に変換できるかどうかを調べます。もしそうなら、あなたはそうするための動きの最小数と結果の方程式を出力することになっています。

入力

入力は、STDINから読み取ることができる文字列で、関数の引数として取得するか、ファイルに保存することもできます。これは、マッチスティック配置を表す方程式であり、次のEBNFを使用して説明できます。

input = term, "=", term ;
term = number | (term, ("+" | "-"), term) ;
number = "0" | (numeralExceptZero , {numeral}) ;
numeralExceptZero = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
numeral = "0" | numeralExceptZero ;

有効な入力の例はになります3+6-201=0+0+8

仕事

各マッチスティックに番号が割り当てられている次の図を検討してください。

マッチ棒の位置

次のように、各入力シンボルを対応するマッチスティックの位置にマッピングします。

0 ↦ 1,2,3,4,5,6
1 ↦ 4,5
2 ↦ 2,3,5,6,8
3 ↦ 3,4,5,6,8
4 ↦ 1,4,5,8
5 ↦ 1,3,4,6,8
6 ↦ 1,2,3,4,6,8
7 ↦ 4,5,6
8 ↦ 1,2,3,4,5,6,8
9 ↦ 1,3,4,5,6,8
- ↦ 8
+ ↦ 8,10
= ↦ 7,9

各入力式は、マッチスティック配列に変換できます。たとえば、方程式「45 + 6 = 92」は次のようになります

ここに画像の説明を入力してください

未使用のマッチ棒はグレー表示されます。あなたの仕事は、方程式を有効にするために再配置する必要があるマッチスティックの最小数を見つけることです。

出力

考えられる3つのケースを区別します。

  • 入力が無効な場合(つまり、上記のEBNFを満たさない場合)、必要なものを出力します。
  • そうでなければ、マッチスティックを再配置して方程式を有効なものに変える方法がある場合、再配置の最小数対応する方程式の両方を出力する必要があります。入力と同様に、出力された方程式も指定されたEBNFを満たさなければなりません。上記の例では、正しい出力は 1and 46+6=52です。結果の方程式に複数の可能性がある場合、それらのいずれかを出力します。
  • それ以外の場合(したがって、入力は有効であるが、方程式を真にする方法がない場合)、出力する必要があります-1

詳細

  • 一致を削除または追加することはできません。つまり、入力がnマッチスティックで構築されている場合、出力も正確にnマッチスティックで構成されている必要があります。
  • 「空の」マッチスティックブロックは、式の最後と最初でのみ許可され、中央では許可されません。だから、例えば、ターニング7-1=67 =6-1簡単に除去することにより、-1左側からわずか3マッチ棒の再編成と右側にそれを追加することが許可されていません。
  • 私は実際のプラスのために、この挑戦の興味深い部分として位置をマッチ棒の数字からのマッピングが表示されないので、20バイトのどちらかが、

    • マッピング(number/operation ↦ matchstick positions)が合理的な方法で保存されているファイルにアクセスする、または
    • プログラミング言語がMapデータ型をサポートしている場合、(number/operation ↦ matchstick positions)-mappingで事前に初期化されたマップにアクセスできると仮定します。たとえば、このマップは次のようになります。{(0,{1,2,3,4,5,6}),(1,{4,5}),(2,{2,3,5,6,8}),(3,{3,4,5,6,8}), ..., (-,{8}),(+,{8,10}),(=,{7,9})}

入力: 1+1=3出力: 1および1+1=2

入力: 15+6=21出力: 0および15+6=21

入力: 1=7出力: -1

入力: 950-250=750出力: 2および990-240=750

入力: 1-2=9出力: 1および1+2=3

入力: 20 + 3=04出力:何でも

勝者

これはなので、最短の正解(バイト単位)が勝ちます。最初の正解が投稿されてから1週間後に勝者が選ばれます。


1
0: 1, 2, 3, 4, 5, 6一貫性のために追加してください
チャールズ

ああ、どういうわけかそれを完全に忘れてしまった!
vauge

@vaugeちょっと '2 = 1-1'-> '2-1 = 1'は3または14の動きを返すはずです。
シエリック

@Ciericは、=(2マッチスティック)と-(1マッチスティック)の位置を切り替えて、すべての数字をそのままにしておくことができるため、3を返すはずです。ただし、2を左に移動する必要がある場合は、必要な移動もカウントする必要があります。
vauge

操作の数に制限はありますか?入力は次のようにできます1+1+2=3-6+10か?出力に関する同じ質問。
Qwertiy

回答:


6

Javascript、1069バイト

かなりの数のテスト式でテストしましたが、今では常に機能しているようです...

function w(t){function B(c,f){d=(c.length>f.length?f:c).split("");e=(c.length>f.length?c:f).split("");longer=Math.max(d.length,e.length);if(0!==d.length&&0!==e.length){c=[];for(x in d)for(y in c[x]=[],e)c[x][y]=1<y-x?-1:function(c,n){r=0;for(j in n)-1<c.indexOf(n[j])&&r++;return c.length+n.length-2*r}(a[d[x]],a[e[y]]);return v=function(f,n){for(var h=f.length-2;0<=h;h--)c[n.length-1][h]+=c[n.length-1][h+1];for(h=f.length-2;0<=h;h--)for(var q=0;q<n.length-1;q++)1>=h-q&&(c[q][h]+=-1==c[q][h+1]?c[q+1][h+1]:Math.min(c[q+1][h+1],c[q][h+1]));return c[0][0]/2}(e,d)}return-1}a=[[1,2,3,4,5,6],[4,5],[2,3,5,6,8],[3,4,5,6,8],[1,4,5,8],[1,3,4,6,8],[1,2,3,4,6,8],[4,5,6],[1,2,3,4,5,6,8],[1,3,4,5,6,8]];a["+"]=[8,0];a["-"]=[8];a["="]=[7,9];a[" "]=[];l=0;p=[];u=[];r=/^([1-9]\d*|0)([+-]([1-9]\d*|0))*=([1-9]\d*|0)([+-]([1-9]\d*|0))*$/;b=/(=.*=|[+=-]{2,}|^[+=-])/;if(!t.match(r))return-1;g=function(c,f,t){if(0===t&&f.match(r)&&eval(f.replace("=","==")))c.push(f);else for(var n in a)t>=a[n].length&&" "!=n&&!(f+n).match(b)&&g(c,f+n,t-a[n].length)};g(p,"",function(c){m=0;for(var f in c)m+=a[c[f]].length;return m}(t.split("")));for(var z in p)k=B(t,p[z]),u[k]||(u[k]=[]),u[k].push(p[z]);for(var A in u)return[A,u[A]];return-1}

まあ、これは答えを提出するのはこれが初めてですので、私は自分自身が勝つことはありません。これは基本的にすべての回答を把握するためのブルートフォースメソッドであり、配列内の最小の回答を取得して返します。最初の引数は長さで、2番目の引数は出力のある配列です。

入力が「1-2 = 9」の場合、出力は[1、["1 + 2 = 3"、 "7-2 = 5"]]です

これが非圧縮コードです:

function ms(s) {
a=[[1,2,3,4,5,6],[4,5],[2,3,5,6,8],[3,4,5,6,8],[1,4,5,8],[1,3,4,6,8],[1,2,3,4,6,8],[4,5,6],[1,2,3,4,5,6,8],[1,3,4,5,6,8]];
a["+"] = [8, 0];
a["-"] = [8];
a["="] = [7, 9];
a[" "] = [];
l = 0;
p = [];
u = [];
r = /^([1-9]\d*|0)([+-]([1-9]\d*|0))*=([1-9]\d*|0)([+-]([1-9]\d*|0))*$/;
b = /(=.*=|[+=-]{2,}|^[+=-])/;
if (!s.match(r)) return -1;
function f(g,h)
{
    d=(g.length>h.length?h:g).split('');
    e=(g.length>h.length?g:h).split('');
    longer=Math.max(d.length, e.length);
    if(0!==d.length&&0!==e.length)
    {
        g=[];
        for(x in d)
        {
            g[x]=[];
            for(y in e)
            {
                g[x][y]=(y-x>1)?-1:function(g, h){r=0;for(j in h)if(g.indexOf(h[j])>-1)r++;return g.length+h.length-2*r;}(a[d[x]],a[e[y]]);
            }
        }
        v=function(d,e)
        {
        for(var y=d.length-2;y>=0;y--) g[e.length-1][y]+=g[e.length-1][y+1];
        for(var y=d.length-2;y>=0;y--)
            for(var x=0;x<e.length-1;x++)
                if(y-x<=1)
                    g[x][y]+=g[x][y+1]==-1?g[x+1][y+1]:Math.min(g[x+1][y+1], g[x][y+1]);
        return g[0][0]/2}(e,d)
        return v
    }
    return -1;
}
g=function(n, s, i){if (i===0 && s.match(r) && eval(s.replace('=','=='))){n.push(s);return;}for (var c in a) if(i>=a[c].length && c!=" " && !(s+c).match(b)) g(n, s+c, i-a[c].length);};
g(p, "", function(q){m=0;for(var t in q)m+=a[q[t]].length;return m}(s.split('')));
for (var i in p)
{
    k=f(s, p[i]);
    if (!u[k]) u[k] = [];
    u[k].push(p[i]);
}
for (var q in u) return [q, u[q]];
return -1;
}

警告:950-250 = 750のような方程式を使用しないでください。45個のマッチスティックを使用し、このコードはブルートフォースを使用するため、javascriptがハングします。


var kループなどで使用する変数を関数の未使用パラメーターとして宣言でき、各宣言で3バイトを節約できると思います。
ロルク

私はさらにいくつかのプログラミング言語を学び、そのバイトカウントを実際にノックダウンするためのそれほど強引な方法を見つけ出すつもりだと思います。
シエリック

距離を計算するときは常に等しい文字を揃えるため、あなたの解決策は正しくないと思います。場合によっては、最適な方法ではありません。たとえば、「2 = 1-1」は3手で「2-1 = 1」に変換できますが、「=」記号を合わせると14手になります。また、先行ゼロを回避する方法がわかりません。たとえば08=8for 80=8は正しくありません。
-nutki

@nutkiええ、私はそれを変えることができると思います。技術的には2を移動して-1のスペースを確保する必要があるため、間違っていると思っていました
-Cieric

@nutkiはい、はい。申し訳ありませんが、今の意味がわかります。さて、正規表現を修正し、編集距離に合わせてコードを変更できるかどうかを確認します。
シエリック

1

Perl、334

ソリューションが1回または2回の移動で到達可能である限り、かなり高速です。解決策がない場合は、最小の場合でも長い間待ち1=7ます。

#!perl -p
@y=map{sprintf"%010b",$_}63,24,118,124,89,109,111,56,127,125,64,192,768;
$y{$z{$y[$c++]}=$_}=$y[$c]for 0..9,qw(- + =);
$"="|";$l=s/./$y{$&}/g;$x{$_}=1;for$m(0..y/1//){
last if$_=(map"$m $_",grep{s/@y/$z{$&}/g==$l&&/^\d.*\d$/&!/\D\D/&!/\b0\d/&y/=//==1&&eval s/=/==/r}keys%x)[0];
$_=-1;s/0/"$`1$'"=~s!1!$x{"$`0$'"}=1!ger/eg for keys%x}

例:

$ time perl ~/matchstick.pl <<<950-250=750
2 990-250=740

real    0m39.835s
user    0m39.414s
sys 0m0.380s

これは、赤道の長さを変更する11=4->のような解決策を見つける2 11=11ことはできませんが、これが許可されるかどうかはわかりません。


1
方程式の長さを変更するソリューションは、質問で言及されたEBNFに従う限り許可されます。したがって、それらは関数によっても検出される必要があります。
vauge

@vauge、ええ、詳細の「空のマッハスティックブロック」セクションから推測できることがわかります。このソリューションには追加しませんが、動作する間はさらに遅くなります。
-nutki

@vauge私は失礼に聞こえたくありませんが、コードが修正されていなくてもカウントされますか?
シエリック

@Ciericこれらのすべてのケースを処理する他のソリューションがない場合、はい、それはカウントされます。ただし、この課題の終わりまでに完全に機能する回答があれば、最短の回答を受け入れます。
-vauge

@vauge OKチェックするだけで、移動数が正しいことを確認するだけで、常に正しい出力方程式が表示されます。
シエリック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.