Giải phương trình với (gần như) bất kỳ số nào bạn thích


27

Cho một chuỗi các ký tự +=-có ít nhất một ký tự =, chèn các số nguyên dương giữa tất cả các ký hiệu và ở đầu và cuối để các phương trình toán học được thỏa mãn.

Ví dụ, đưa ra đầu vào

+-=-=

bạn cần chèn các số nguyên dương từ A đến F như thế này

A+B-C=D-E=F

như vậy mà các phương trình đều hài lòng, tức A + B - CD - EFtất cả đều cùng một số.

Có nhiều cách có thể để làm điều này vì, miễn là các phương trình hoạt động, bất kỳ tập hợp số nguyên dương nào cũng có thể được sử dụng. Mỗi dòng ở đây là một đầu ra hợp lệ có thể để đầu vào +-=-=:

2+3-4=6-5=1
1+1-1=2-1=1
4+2-4=4-2=2
100+1-10=182-91=91
89+231-77=1024-781=243

Lưu ý rằng giá trị của các biểu thức không bắt buộc phải là số nguyên dương giống như các số được chèn vào. Ví dụ, đầu vào đã cho, -=-các đầu ra 1-10=8-17(evals đến -9) và 10-1=17-8(evals đến 9) đều có giá trị như nhau. Tất nhiên đối với một số đầu vào như =không thể có âm là biểu thức vì chỉ 5=5có thể chèn các số dương như thế .

Cũng lưu ý rằng số 0 không phải là số nguyên dương.

Mã ngắn nhất tính bằng byte thắng.

Bạn có thể xuất các số dưới dạng danh sách thay vì chèn chúng trực tiếp vào chuỗi. Nếu bạn xuất chuỗi, có thể có khoảng trắng phân cách ký hiệu và số. Vì vậy, cho đầu vào +-=-=, đầu ra

2, 3, 4, 6, 5, 1

hoặc là

2 + 3 - 4 = 6 - 5 = 1

tương đương với đầu ra

2+3-4=6-5=1

Các trường hợp thử nghiệm

Input | One Possible Output
= | 1=1
== | 2=2=2
+= | 1+3=4
=+ | 2=1+1
-= | 30-10=20
=- | 1=2-1
=-= | 3=7-4=3
=+= | 2=1+1=2
=== | 100=100=100=100
+=- | 3+2=7-2
-=+ | 7-2=3+2
+=+ | 3+3=3+3
-=- | 1-10=8-17
--= | 60-1-1=58
++= | 60+1+1=62
-+= | 60-9+1=52
+-= | 60+9-1=68
+-=-= | 2+3-4=6-5=1
--=-- | 2-1-1=2-1-1
==-== | 47=47=50-3=47=47
=++=+-=-+=--= | 3=1+1+1=3+1-1=1-1+3=5-1-1=3
+--++-=-+-+- | 35+10-16-29+20+107-1000=5-4+3-2+1-876
====== | 8=8=8=8=8=8=8


Chúng ta có thể giả sử bất kỳ giới hạn trên về độ dài của công thức?
xnor

2
@xnor Bạn có thể giả sử đầu vào dài dưới 2 ^ 16 ký tự nếu điều đó có ích.
Sở thích của Calvin

Câu trả lời:


16

Võng mạc , 58 byte

[-+]
$&1
\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&
+`1_

1+
$.&

Hãy thử trực tuyến!

Giải pháp thay thế ở cùng số byte:

((\+)|(-))*
$._$*1$#3$*1$#2$*_$&
+`1_

([+-])1*
$+1
1+
$.&

Hãy thử trực tuyến!

Giải trình

Ý tưởng cơ bản là biến tất cả các +s và -s thành đơn giản +1-1hoạt động và sau đó trả trước một số lượng đủ lớn để làm cho tất cả các phương trình hoạt động. Để làm cho các phương trình khớp nhau, chúng ta chỉ cần thêm một số tương tự cho mỗi số đó, sau đó giảm từng cái cho từng số +1và tăng từng số cho mỗi số -1sau mỗi số đó. Vì chúng ta sẽ làm việc với các số đơn nguyên, điều đáng chú ý duy nhất là số đầu tiên cần đủ lớn để chúng ta có thể giảm nó đủ 1 lần.

[-+]
$&1

Chúng tôi bắt đầu bằng cách chèn một 1sau mỗi -hoặc +.

\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&

Việc \Bđảm bảo rằng các kết quả khớp này nằm ở đầu của đầu vào hoặc giữa a =và a +hoặc -, tức là tất cả các vị trí mà chúng ta muốn chèn số dẫn đầu của biểu thức. Phần ((\+1)|(-1))*sau đó chỉ đơn giản là đếm số +1s và -1s trong các nhóm 23tương ứng. Bây giờ hãy phá vỡ chuỗi thay thế:

$._$*1   # For each character in the current string, insert a 1. This is
         # an offset which is the same for each expression and is guaranteed
         # to be large enough that all subsequent +1s can be cancelled.
$#3$*1   # For each -1, insert a 1.
$#2$*_   # For each +1, insert a _.
$&       # Re-insert the string of +1s and -1s.
+`1_

Liên tục thả 1_từ chuỗi, áp dụng hủy yêu cầu từ +1s.

1+
$.&

Cuối cùng, thay thế tất cả các chuỗi của 1s bằng độ dài của chúng để chuyển đổi từ đơn nguyên sang thập phân.


8

Python 2 , 76 byte

lambda e:sum([[len(e+s)-2*s.count('+')]+[1]*len(s)for s in e.split('=')],[])

Hãy thử trực tuyến!


3
Bạn có thể thêm một lời giải thích?
Sở thích của Calvin

1
@HelkaHomba Ý tưởng khá đơn giản: đầu tiên hãy lấy từng đoạn của đầu vào được phân chia bằng các dấu bằng. Chọn số đầu tiên của mỗi chunk được eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs. Sau đó, vì tất cả các số khác trong khối là số, nên tổng số cho khối này hoạt động eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len. Độ dài phương trình phải là dương, vì vậy mọi thứ đều hoạt động.
FryAmTheEggman

6

Trăn 2, 199 179 178 172 162 158 156 152 151 byte

Cách quá dài, nhưng giải pháp rất dễ tạo ra.

from itertools import*
i=input()
k='%s'
s=k+k.join(i)+k
for p in product(*[range(1,65537)]*-~len(i)):
    if eval((s%p).replace('=','==')):print s%p;break

Dùng thử trực tuyến

Điều này sẽ thử mọi khả năng cho đến khi nó tìm ra giải pháp. Chương trình cực kỳ chậm. Nó cũng thực hiện thay thế chuỗi mỗi lần lặp. Chỉnh sửa "172" làm cho nó chậm hơn đáng kể , vì thay vì bắt đầu với một phạm vi nhỏ, nó bắt đầu ở mức tối đa. Ví dụ: các đầu vào -=hoặc =+phải thử 2 ** 32 lần thử trước khi đạt được giải pháp.

Để tăng tốc chương trình, sử dụng phiên bản có 178 byte từ lịch sử chỉnh sửa.


Không phải rangetrong python2 tạo toàn bộ phạm vi như một danh sách ngay lập tức? IIRC bạn có thể tăng tốc bằng cách sử dụng xrangethay vào đó, vì tôi nghĩ đó là phiên bản tải lười biếng (Python3 sử dụng lười biếng làm mặc định range)
Delioth

1
@Delioth Điều đó sử dụng một byte khác, mặc dù. Mục tiêu là loại bỏ byte. Ngoài ra, điều đó thực sự sẽ không cung cấp nhiều tốc độ, vì phần lớn sự chậm lại là từ số lần lặp chứ không phải việc tạo danh sách, chỉ xảy ra một lần. Tôi đã chạy print range(1,65537)và nó đã hoàn thành trong 0,034 giây.
mbomb007

Chà, tất nhiên - nhiều hơn một "điều này có thể tăng tốc nó với chính xác cùng một phương pháp", vì lo lắng về việc mất quá nhiều thời gian. Bộ nhớ đập có thể gây ra sự chậm lại đáng kể. Ngoài ra, bạn có thể cắt một số byte (có thể chỉ 1) bằng cách không cài đặt l=..., nhưng đặt quyền đó vào product(range(...),repeat=len(s)+1). Nếu bạn cần dấu ngoặc đơn, nó chỉ lưu một byte (\ n)
Delioth

@Delioth Ngay cả khi tôi cần parens xung quanh len(s)+1, tôi có thể sử dụng -~len(s)thay thế, điều này sẽ không yêu cầu parens.
mbomb007

À, đúng rồi. Tôi luôn quên các thao tác và thủ thuật bitwise - phải là số điện thoại hoạt động trên javascript ngoại tuyến đang đảm nhận chuyên môn Python của tôi!
Delioth

5

JavaScript (ES6), 92 82 byte

Chơi gôn 8 byte với một mẹo từ @xnor

let f =
x=>x.split`=`.map(q=>(x+q).length-2*~-q.split`+`.length+[...q,''].join(1)).join`=`
<input oninput="if(/^[+=-]+$/.test(value))O.innerHTML=f(value)" value="="><br>
<pre id=O>1=1</pre>

Mẹo ở đây là chèn một 1sau mỗi +hoặc -sau đó thêm vào mỗi biểu thức số làm cho biểu thức bằng độ dài của đầu vào. Bằng cách này, chúng tôi có thể đảm bảo rằng số luôn luôn dương; vì luôn có ít nhất 1 =trong chuỗi, số +s không bao giờ có thể đạt tới độ dài của chuỗi, vì vậy phần còn lại luôn luôn ít nhất 1. Bạn có thể xác minh điều này bằng cách nhập một số tùy ý+ s vào đoạn trích ở trên.


5

Python 2 , 120 119 byte

-1 byte nhờ mbomb007

a=['1'+(n and('1'.join(n)+'1'))for n in input().split('=')]
print'='.join(`max(map(eval,a))-eval(c)+1`+c[1:]for c in a)

Hãy thử trực tuyến! hoặc Xác minh tất cả các trường hợp kiểm tra

Đầu tiên tôi chèn 1vào mọi vị trí, để kiểm tra giá trị cao nhất, sau đó thêm nó dưới dạng bù trên mỗi phương trình. Điều này hoạt động vì bạn không thể thêm số âm, do đó, kết quả tối thiểu được đưa ra bởi số lượng +trong phương trình chỉ có +.


Bạn có thể loại bỏ một vài khoảng trắng.
mbomb007

5

GNU Prolog, 156 byte

x(L,R,V)-->{E#>0},({L=[E|R],E=V};x(L,[E|R],X),("+",{V#=X+E};"-",{V#=X-E})).
q(L,R,V)-->x(L,T,V),({T=R};"=",q(T,R,V)).
s(Q,L):-q(L,[],_,Q,[]),fd_labeling(L).

Giải trình

Chúng ta đã có một loạt các phương trình để giải, vậy tại sao không sử dụng một bộ giải phương trình thực tế?

xvề cơ bản là một đánh giá phương trình cho các phương trình của hình thức +-+; ngoài chính phương trình, nó còn có hai đối số bổ sung (một danh sách khác biệt L,Rchứa các giá trị của phương trình và một giá trị Vmà phương trình ước tính). Như thường lệ trong Prolog, nó có thể được sử dụng theo bất kỳ cách nào (ví dụ: bạn có thể chỉ định Vvà nhận L,R, chỉ định L,Rvà nhận a V, chỉ định cả hai và xác minh rằng giá trị là chính xác hoặc chỉ định trong trường hợp nào các ràng buộc phù hợp sẽ được đặt trên cả hai VL,R). "Phần tử hiện tại" của L,Rđược đặt tên Evà chúng tôi cũng bao gồm một xác nhận rằngElớn hơn 0 (vì câu hỏi yêu cầu sử dụng số dương). Hàm này dài dòng hơn một chút so với tôi muốn, ví dụ tôi phải viết để hoạt động.[E|R]khớp mẫu / không khớp hai lần, do thực tế là các danh sách là liên kết phải nhưng phép cộng và phép trừ là liên kết trái. Đáng buồn thay, chúng ta cần sử dụng một danh sách thực tế, thay vì phát minh ra loại danh sách liên kết bên trái của chúng ta ra khỏi các ô khuyết điểm, chofd_labeling

qlà tương tự x, nhưng cũng bao gồm =. Về cơ bản nó chỉ gọi x, và chính nó đệ quy. Ngẫu nhiên, đó là một minh chứng rất rõ ràng về cách danh sách khác biệt hoạt động, cho thấy rằng bạn có thể ghép hai danh sách khác nhau L,TT,Rvào một danh sách khác biệt L,R. Ý tưởng cơ bản là danh sách khác biệt là một hàm lấy một đối số Rvà trả về một giá trịLRchính danh sách đó được đặt trước nó. Do đó, bằng cách xác định đối số của một danh sách khác biệt và giá trị trả về của một danh sách khác, chúng ta có thể soạn các hàm và do đó ghép các danh sách.

Cuối cùng, sfunciton thực sự giải quyết nhiệm vụ trong câu hỏi, là một hàm bao bọc gọi qbằng các đối số. Chúng tôi chuyển đổi danh sách khác biệt thành một danh sách thông thường bằng cách cung cấp []làm đối số của nó và sử dụngfd_labeling để tìm một giải pháp cho phương trình mà chúng tôi đã xây dựng. (Theo mặc định, có vẻ như cài đặt giá trị thành 1 nếu không có lý do gì để đặt chúng thành một thứ khác. Tuy nhiên, nó có thể được định cấu hình; value_method(random)cung cấp các giải pháp "thú vị" hơn so với đặt 1 ở mọi nơi, ví dụ, và vẫn rất nhanh. )

Sản lượng mẫu

Với chương trình như đã viết:

| ?- s("=++=+-=-+=--=", V).

V = [3,1,1,1,3,1,1,3,1,1,5,1,1,3] ?

Nếu tôi làm cho chương trình dài hơn một chút để thêm a value_method(random), kết quả sẽ thay đổi, nhưng trông giống như thế này:

| ?- s("=++=+-=-+=--=", V).

V = [68,6,12,50,85,114,131,45,3,26,71,1,2,68] ? 

Trong cả hai trường hợp, ?ở cuối đầu ra có nghĩa là có thể có nhiều hơn một giải pháp. (Tất nhiên, trong trường hợp này, chúng tôi biết rằng có nhiều hơn một giải pháp!)


4

Toán học, 116 byte

Join@@(Prepend[#^2,1-Min[Tr/@c]+Tr@#]&/@(c=Characters@StringSplit["0"<>#<>"0","="]/."+"->-1/."-"->1/."0"->Nothing))&

Hàm thuần túy lấy một chuỗi làm đầu vào và trả về một danh sách các số nguyên dương. Chiến lược cơ bản: chúng tôi chỉ bao giờ thêm 1 và trừ 1 và chúng tôi chọn các số ban đầu trong mỗi biểu thức để làm cho mọi thứ đều bằng nhau.

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1 sẽ phân tách chuỗi đầu vào ở mỗi dấu bằng, sau đó thay thế từng chuỗi + bằng -1và mỗi -bằng 1. Tuy nhiên, nếu có một dấu bằng ở đầu hoặc cuối, thì nó sẽ bị bỏ qua. Do đó, chúng tôi thêm một ký tự mới vào mỗi đầu ( "0"<>#<>"0") và làm cho nó biến mất sau khi quá trình tách chuỗi hoàn thành ( /."0"->Nothing).

Tổng số của mỗi danh sách con bây giờ bằng một số nguyên mà chúng ta có thể đặt trước +s và -s để làm cho mỗi biểu thức bằng nhau. 1-Min[Tr/@c]là số nguyên nhỏ nhất mà chúng ta có thể thêm vào mỗi tổng để làm cho tất cả chúng dương. Vì vậy, Prepend[#^2,1-Min[Tr/@c]+Tr@#]&lấy từng danh sách con (lần ^2lượt tất cả các mục của chúng thành 1) và trả trước tổng số được thay đổi bởi số nguyên bù nhỏ nhất này. Các danh sách kết quả được Joined với nhau để tạo ra đầu ra.


3

Ruby, 76

->s{(?1+s.gsub(/./){|a|a+?1}).split(?=).map{|e|e[0]="#{5**8-eval(e)}";e}*?=}

Giá trị mục tiêu cho các biểu thức được cố định ở 5**8âm 1 vì lý do chơi gôn! Ban đầu tôi đang sử dụngs.size+1 trừ 1.

Ungolfed trong chương trình thử nghiệm

f=->s{(?1+s.gsub(/./){|a|a+?1}).           #add a 1 at the beginning and after every symbol
       split(?=).                          #split into an array of expressions at = signs
       map{|e|                             #for each expression string
         e[0]="#{5**8-eval(e)}";e          #change the first number to 5**8-eval(e)
       }*?=                                #and rejoin the strings
}


puts f["="] 
puts f["=="] 
puts f["+="] 
puts f["=+"]
puts f["-="]
puts f["=-"]
puts f["=-="]
puts f["=+="]
puts f["==="]
puts f["+=-"]
puts f["-=+"]
puts f["+=+"]
puts f["-=-"]
puts f["--="]
puts f["++="]
puts f["-+="]
puts f["+-="]
puts f["+-=-="]
puts f["--=--"]
puts f["==-=="]
puts f["=++=+-=-+=--="]
puts f["+--++-=-+-+-"]
puts f["======"]

Đầu ra

390624=390624
390624=390624=390624
390623+1=390624
390624=390623+1
390625-1=390624
390624=390625-1
390624=390625-1=390624
390624=390623+1=390624
390624=390624=390624=390624
390623+1=390625-1
390625-1=390623+1
390623+1=390623+1
390625-1=390625-1
390626-1-1=390624
390622+1+1=390624
390624-1+1=390624
390624+1-1=390624
390624+1-1=390625-1=390624
390626-1-1=390626-1-1
390624=390624=390625-1=390624=390624
390624=390622+1+1=390624+1-1=390624-1+1=390626-1-1=390624
390624+1-1-1+1+1-1=390625-1+1-1+1-1
390624=390624=390624=390624=390624=390624=390624

2

PHP, 207 204 197 114 byte

tiếp cận trực tiếp: ngắn hơn nhiều và nhanh hơn

foreach(explode("=",$argn)as$t)echo"="[!$c],strlen($argn)+($c=count_chars($t))[45]-$c[43],@chunk_split($t,!!$t,1);

Chạy với echo '<input>' | php -nR '<code>'hoặc kiểm tra nó trực tuyến .

phá vỡ

foreach(explode("=",$argn)as$t) // loop through terms
    echo                            // print ...
        "="[!$c],                       // 1. "=" if not first term
        strlen($argn)                   // 2. maximum number
            +($c=count_chars($t))[45]   //    + number of "-"
            -$c[43],                    //    - number of "+"
        @chunk_split($t,!!$t,1);        // 3. each operator followed by "1"
  • !$clà đúng trong lần lặp đầu tiên, được sử dụng để 1lập chỉ mục chuỗi; "="[1]trống rỗng
    Sau đó, $cđược đặt và !$csai, chuyển thành0"="[0]là ký tự đầu tiên.
  • Giá trị tối đa cho bất kỳ nhu cầu kỳ hạn nào không vượt quá số lượng cộng +1;
    vì vậy chúng tôi chắc chắn an toàn với độ dài của đầu vào. Tất cả các điều khoản sẽ đánh giá điều đó.
  • chunk_split($s,$n,$i)chèn $isau mỗi $nký tự của $s- và ở cuối.
    Để ngăn các điều khoản trống chuyển sang 1, một lỗi được buộc bằng cách đặt độ dài khối thành 0.

1

Röda , 112 110 109 byte

f x{[(`:$x:`/"=")()|{|p|p~=":",""a=p;a~=`\+`,""b=p;b~="-","";["=",#x-#b+#a];{(p/"")|{|o|[o,"1"*#o]}_}}_][1:]}

Hãy thử trực tuyến!

Chức năng phân chia không hoạt động như tôi dự định với chương trình này. Ví dụ,split("", sep="") trả về một chuỗi trống thay vì không có gì. Làm thế nào là hợp lý? Do đó, chương trình này lớn hơn gần 20 byte so với những gì có thể nếu ngữ nghĩa phân tách là lý tưởng.

Ý tưởng của câu trả lời này là chúng ta biết rằng độ dài của chuỗi đầu vào phải lớn hơn hoặc bằng giá trị của phương trình, vì vậy chúng ta xác định giá trị của phương trình là độ dài của chuỗi. Đối với mọi phần của phương trình, chúng tôi nghĩ rằng mọi toán tử đang +1hoặc-1 trừ và thêm chúng vào giá trị của phương trình.

Ung dung:

function f(x) {
    /* Adds ":"s around the string to prevent "=" being split wrong. */
    [split(`:$x:`, sep="=") | for p do
        p ~= ":", ""          /* Removes colons. */
        a := p; b := p        /* Initializes a and b to be p. */
        a ~= "\\+", ""        /* The lengths of a and are now equal to the */
        b ~= "-", ""          /* numbers of "-" and "+" characters in x. */
        push("=", #x-#b+#a)   /* Prints "=" and the value of the equation */
                              /* minus number of "+"s plus number of "-"s. */
        split(p, sep="") | for o do /* For each operator: */
            push(o)                 /* Prints the operator. */
            push(1) if [o != ""]    /* Prints 1 unless the operator is "". */
        done
    done][1:] /* Removes the first character of the output ("="). */
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.