Matematik Problem Gösterimini Çöz


14

Her biri bir tamsayı verilen sonsuz sayıda ödev problemim olduğunu (!) Varsayalım.

Matematik Problem Gösterimi, problem tanımlayıcılarını kullanarak problemin alt kümelerini tanımlamak için kullanılan bir gösterimdir.

Bir MPN ifadesi birkaç şeyden oluşabilir:

  • Tek bir değer. Bu sayı içeren bir grubunu temsil eder: 99 -> {99}.
  • Basit bir ürün yelpazesi. Bu aralığın başından sonuna kadar bütün sayıları içeren kümesini temsil: 10~13 -> {10, 11, 12, 13}. Sol veya sağ taraflar eksikse, sırasıyla -Infinity veya Infinity olduğu varsayılır ~10 -> {x|x ≤ 10}:; ~ -> ℤ.
  • Bir MPN ifadesi, ardından "atlama" ve başka bir MPN ifadesi. Bu iki set farkını temsil eder: 10~20 skip 12~14 -> {10, 11, 15, 16, 17, 18, 19, 20}.
  • Virgülle ayrılmış iki MPN ifadesi. Bu iki takım birlikteliğini temsil eder: 1,8~9,15~17 -> {1,8,9,15,16,17}.

"Atla" operatörü, virgül operatörüne göre daha sıkı bağlanır, bu nedenle 16,110~112 skip 16 -> {16,110,111,112}(16 kümeye dahil edilmez {110,111,112}, bu nedenle hariç tutma 16 fark etmez.)

Ayrımcılık için parantez içine ifadeler de koyabilirsiniz: 1~9 skip (2~8 skip (3~7 skip (4~6 skip 5))) -> {1,3,5,7,9}

Bu dilbilgisi:

<expr>  ::= "(" <expr> ")"
         || <number>
         || [<number>] "~" [<number>]
         || <expr> "skip" <expr>
         || <expr> "," <expr>

Göreviniz iki girdi alan bir program yazmaktır:

  • MPN ifadesi
  • Bir sayı

ve bu sorunun MPN ifadesi tarafından tanımlanan kümede olup olmamasına bağlı olarak bazı doğruluk veya falsey değeri verir.

Özellikler

  • İlk girişin iyi biçimlendirilmiş bir MPN ifadesi olduğunu varsayabilirsiniz (yani yukarıdaki dilbilgisi ile eşleşir)
  • MPN ifadesindeki sayılar her zaman tamsayıdır. Negatif veya sıfır olabilirler, ancak asla kesirli bir kısmı olmayacaktır.
  • Bu , bu nedenle (bayt olarak ölçülen) en kısa geçerli gönderim kazanır.
  • İsterseniz ~ve için farklı karakterler kullanabilirsiniz ,.

Test Durumları

10~20             14 -> True
10~20             20 -> True
10~20 skip 14~18  17 -> False
~ skip 6          8  -> True
16,17 skip 16     16 -> True
(16,17) skip 16   16 -> False
~10,5~            8  -> True
~10,5~            4  -> True
6 skip 6,~        6  -> True

Operatörleri temsil etmek için başka karakterler kullanmak mümkün mü? Örneğin, ~
rahnema1

1
@ için rahnema1 ~ve ,ancak için skip.
Esolanging Fruit

3
4 için ~ 10,5 ~ neden yanlış? Çünkü bu, - sonsuzluğun 10 ve 5'in sonsuzluğa birleşmesidir, ilki 4
ev3commander

@ ev3commander Düzenlendi. Test senaryolarımı hep mahvederim. Bahse girerim, onları eklemezsem zorluklarım daha net olurdu: P
Esolanging Fruit

1
Challenger5 @ Ben bir test vakası ekledim 6 skip 6,~ben inanıyorum Ben doğru yorumlanır ettik. Diğer 2 cevap şimdiye kadar tatmin etmiyor (yine doğru yorumladığımı varsayarak). Yanlış anladıysam, lütfen düzeltin ve açıklığa kavuşturun, ancak benim anlayışımdan, herhangi bir şeyle eşleşmelidir (hiçbir şeyle eşleşmeyen bir setin birleşimidir). Bunlar, daha önce bahsettiğim, çözümlerimizi test ederken çok yardımcı olabileceğini düşündüğüm türler.
Briantist

Yanıtlar:


3

PowerShell , 189195 bayt

param($m,$q)('$m',"'(\d*)~(\d*)','($q-ge(`$1)-and$q-le(`$2))'","'\(\)',$q","'((?<=,|skip )\d+|\d+(?=,| skip))','($q-eq`$1)'","'skip','-and!'"-join'-replace'|iex|% Sp* ','|%{"($_)"})-join'-or'|iex

açıklama

Sonsuzlukların bunu diziler oluşturmak ve değerleri test etmek için savunulamaz hale getirdiğini erken fark ettim.

Aralıklara baktım ama .Net'te gerekli aralığa sahip değiller (aralığın uzunluğu işaretli (32 bit) bir tam sayı ile sınırlıdır, bu nedenle aralığı işaretli bir 32 bit int ile sınırlamak uygun olsa bile , Tüm aralıkları idare edemezdim.

Bu yüzden bunu sadece başlangıç ​​ve bitiş açısından düşünmeye başladım ve sonuçta bir dizi boolean testi ve bir MPN'yi PowerShell'in anladığı bir boolean ifadeye dönüştürmek için bir grup regex'in yerini almaya başladım.

Temelde bunu birkaç kurala ayırdım:

  • Aralıkların çalışması daha kolaydı çünkü her iki tarafta da ifade olamıyorlardı, ancak açık uçluluk kısa bir süre içinde uygulanacak bir acıydı. Öncül demek 2~8gibidir n >=2 && n <=8, ancak uçlardan biri eksik olduğunda &&ve eksik tarafı dışarıda bırakın . Her ikisi de eksik olduğunda, başlangıçta sadece onunla değiştirecektim $true. Yaptığım şey, eksik tarafları gerçekten test etmek değildi, ancak her bir sayıyı sarmayı başardım ().
  • ve sonra boş parantezleri ()girdi değeriyle değiştiren düz bir ikame yapın . Bu nedenle, ~8giriş değeri olan bir MPN durumunda 55, ilk değiştirme üretilecek (55-ge()-and55-le(8)), daha sonra ikinci değiştirme, bunu yapmak için (55-ge55-and55-le(8))esasen aralığın bu bölümünü geçersiz kılacaktır .
  • Daha sonra MPN'deki bireysel sayılarla uğraşmak zorunda kaldım, ancak daha önce eklediğim sayılarla uğraşmamaya dikkat etmeliydim. Gerçekten sadece virgülle ,ayrılmış listelerdeki sayılar ve skipa'dan önce veya sonra tek tek sayılar , bu yüzden talihsiz uzun bakışlar kullandım.
  • skiptemelde aynıdır -and -notben düz bir yerine yapmak skipiçin -and!(için !kestirme kullanarak -not).
  • Bir sonraki zor şey, kalan virgüller için düşük öncelik sırasıydı. Başlangıçta sadece onları değiştirdim -orama sonraki ifadeleri hesaba katmadı, bu yüzden 16,17 skip 16kod üretiyordu ($n-eq16)-or($n-eq17) -and! ($n-eq16). Parantez gerekiyordu, ancak bu düz bir değiştirmeyle işe yaramaz görünüyordu. Virgül hariç tüm diğer şeyler değiştirildiğinden ve en düşük önceliğe sahip olduklarından, oluşturulan tüm dizeyi kalan virgüllere böldüm, sonra her öğeyi parantez içine aldım ve yeniden birleştirdim -or.

Sonuçta, oluşturulan kod yürütmek için sadece Invoke-Expression( iex) piped edilir ve sonra boolean sonucunu alırız ( burada sonuç yerine üretilen kodu görebilirsiniz ).

Bu çok uzun sürdü ve eminim birkaç bayt daha sıkmak için bir yer var, ama artık bakamıyorum :-p


2

Perl, 99 130 bayt

sub f{($_,$n)=@_;s/(-?\d+)?~(-?\d+)?|(-?\d+)/!(defined$3?$n!=$3:length$1&&$1>$n||length$2&&$n>$2)+0/ge;s/skip/&&!/g;s/,/||/g;eval}

Ideone üzerinde deneyin.

Ungolfed:

sub f {
    my ($e, $n) = @_;

    $e =~ s/(-?\d+)?~(-?\d+)?|(-?\d+)/ (defined($3) ? $n == $3 : (!length($1) || $n >= $1) && (!length($2) || $n <= $2)) + 0 /ge;
    $e =~ s/skip/ && ! /g;
    $e =~ s/,/ || /g;

    return eval($e);
}

1
Giriş -2 için ~ -2 başarısız olur. Ayrıca yerleştirirken -? Her üç \ d * önce
Kjetil S.

@KjetilS. Negatif sayılar ve sıfır için düzeltildi.
Denis Ibaev

güzel kodu (tam şişmiş gramer sıklıkla gerekli değildir ayrıştırma, regexes kolaydır)
Kjetil S.

1

JavaScript (ES6), 221 292 287 309 274 277 278 bayt

(Okx sayesinde -5 bayt)

(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))

Vay. Bu, tüm uç durumlar nedeniyle kolay değildi, ama sanırım başardım. Sadece umut kullanılan normal ifadeler kırabilir hiçbir özel durumlar vardır. Mümkün olduğunca bu golf olacak.

Test Parçacığı

D=(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))
MPN Expression:<input type="text" value="1~9 skip (2~8 skip (3~7 skip (4~6 skip 5)))" id="MPN"></input>
<br>
Integer:<input type="number" id="INT" value=6></input>
<input type="button" value="Submit" onclick="T=r=>document.getElementById(r).value;console.log(D(T('MPN'),T('INT')))"></input>


@AriaAx Şimdi çalışmalı.
R. Kap

@ R.Kap 1/0için kullanabilirsiniz Infinity.
Okx

@ R.Kap Olması gerektiğine inandığım 6ifade ile değer denedim ama geri döndü . 6 skip 6,~truefalse
Briantist

@briantist Aslında inanmak gerekir dönmek falseolarak skipuygulanır şeyi (onu takip 6,~bu durumda) o olduğu sürece değil parantez içine sarılmış. Bu nedenle artık dönmelidir inanıyoruz trueüzerine (6 skip 6),~yerine 6 skip 6,~tamsayı girişi ile 6.
R. Kap

Diğer bir deyişle, set ile set arasındaki farkı temsil ettiği için hiçbir şeyle6 skip 6,~ eşleşmemelidir . {6}{6,-Infinity...Infinity}
R. Kap

0

Röda + bc, 183 bayt

f x{{["x=",x,"\n"];replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",x;["\n"]}|exec"bc"}

Bu PowerShell yanıtına benzer (ya da sanırım PowerShell'i anlamıyorum). Bir değişken olarak numarasını ve bu gibi giriş akımında bir değer olarak kodu alır: main { push("1~9") | f(5) }.

Bence işe yarıyor, en azından tüm test senaryolarını çözüyor. Aşağıdaki komut dosyası bunu doğrulamak için kullanılabilir.

main {
    readLines("/tmp/tests.txt") | split(sep=";") | for code, num, ans do
        push(code, " -> ")
        print(code) | replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",num
        a := push(code) | f(num) | head()
        result := push("OK") if [ (a = "0" and ans = "False") or (a = "1" and ans = "True") ] else push("FAIL")
        print code, " ; ", num, " -> ", a, " ", ans, " (", result, ")\n"
    done
}

Ve testler:

10~20;14;True
10~20;20;True
10~20 skip 14~18;17;False
~ skip 6;8;True
16,17 skip 16;16;True
(16,17) skip 16;16;False
~10,5~;8;True
~10,5~;4;True
6 skip 6,~;6;True
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.