Знайдіть інтегральні корені многочлена


19

Виклик

Завдання полягає в тому, щоб написати програму, яка приймає коефіцієнти будь-якого n-ступеня поліноміального рівняння як вхідні та повертає інтегральні значення x, для яких рівняння справедливо. Коефіцієнти будуть надані як вхідні дані в порядку зменшення або збільшення потужності. Ви можете вважати всі коефіцієнти цілими числами .

Вхід і вихід

Вхідними даними будуть коефіцієнти рівняння у порядку зменшення або збільшенні потужності. Ступінь рівняння, тобто максимальна потужність x, завжди на 1 менше, ніж загальна кількість елементів у вході.

Наприклад:

[1,2,3,4,5] -> represents x^4 + 2x^3 + 3x^2 + 4x + 5 = 0 (degree = 4, as there are 5 elements)
[4,0,0,3] -> represents 4x^3 + 3 = 0 (degree = 3, as there are 3+1 = 4 elements)

Вихід повинен бути лише різними інтегральними значеннями x, які задовольняють заданому рівнянню. Всі вхідні коефіцієнти є цілими числами, а вхідний многочлен не буде нульовим многочленом . Якщо для даного рівняння немає рішення, то вихід не визначений.

Якщо рівняння має повторювані корені, відобразіть цей конкретний корінь лише один раз. Значення можна виводити в будь-якому порядку. Також припустимо, що вхід буде містити щонайменше 2 числа.

Приклади

[1,5,6] -> (-3,-2)
[10,-42,8] -> (4)
[1,-2,0] -> (0,2)
[1, 1, -39, -121, -10, 168] -> (-4, -3, -2, 1, 7)
[1, 0, -13, 0, 36] -> (-3, -2, 2, 3)
[1,-5] -> (5)
[1,2,3] -> -

Зауважимо, що рівняння у другому прикладі також має корінь 0,2, але воно не відображається, оскільки 0,2 не є цілим числом.

Оцінка балів

Це , тому найкоротший код (у байтах) виграє!


7
Примітка. Перед тим, як закрити голосування, врахуйте, що це питання не є дублікатом цього . Я можу придумати хоча б один підхід до цієї проблеми, який не буде тривіально модифікованим для іншого виклику (хоча я не говорю про те, що вам залишається; P).
Ерік Аутгольфер

Чи можемо ми припустити, що нам потрібно лише повернути коріння в цілі межі нашої мови? Або алгоритм повинен працювати, навіть якщо діапазон типів цілих чисельних мов був збільшений, але поведінка залишилася колишньою.
Οurous

1
Чи можемо ми також використовувати рідний тип поліномів, якщо ваша мова підтримує це?
недолік

1
Чи приймаються програми, які працюють вічно, якщо немає рішення?
Джек М

1
Ось щоб все було просто.
Маніш Кунду

Відповіді:


6

MATL , 13 12 байт

|stE:-GyZQ~)

Спробуйте в Інтернеті!

Тут використовується факт що для цілих коефіцієнтів абсолютне значення будь-якого кореня суворо менше, ніж сума абсолютних значень коефіцієнтів.

Пояснення

Розглянемо вклад [1 5 6]як приклад.

|    % Implicit input. Absolute value
     % STACK: [1 5 6]
s    % Sum
     % STACK: 12
t    % Duplicate
     % STACK: 12, 12
E    % Multiply by 2
     % STACK: 12, 24
:    % Range
     % STACK: 12, [1 2 ... 23 24]
-    % Subtract, elemet-wise
     % STACK: [11 10 ... -11 -12]
G    % Push input again
     % STACK: [11 10 ... -11 -12], [1 5 6]
y    % Duplicate from below
     % STACK: [11 10 ... -11 -12], [1 5 6], [11 10 ... -11 -12]
ZQ   % Polyval: values of polynomial at specified inputs
     % STACK: [11 10 ... -11 -12], [182 156 ... 72 90]
~    % Logical negation: turns nonzero into zero
     % STACK: [11 10 ... -11 -12], [0 0 ... 0] (contains 1 for roots)
)    % Index: uses second input as a mask for the first. Implicit display
     % STACK: [-3 -2]

3
В якості альтернативи теоремі Руша теорема раціональних коренів також буде достатньою для обгрунтування використовуваної вами межі. За теоремою раціональних коренів усі цілі корені обмежені в абсолютній величині максимальними абсолютними значеннями коефіцієнтів, більш жорсткими, ніж сумою. Або ще жорсткіше, за абсолютним значенням "останнього" ненульового коефіцієнта - тобто коефіцієнта найменшої потужності x, який має ненульовий коефіцієнт. (Напевно, це не допомагає зберегти жодних байт, просто альтернативне підтвердження, оскільки RRT, мабуть, більш звичний, ніж Rouche, для більшості людей.) :)
mathmandan,

1
@mathmandan такий підхід на три байти довше: спробуйте тут , хоча я впевнений, що я пропустив трюк чи два
Джузеппе

@Giuseppe Дякую обом. Можливо X>t_w&:GyZQ~), але все ж 13 байт
Луїс Мендо

1
... але я знайшов більш коротку альтернативу для асортименту
Луїс Мендо

5

Лушпиння , 10 9 байт

-1 байт завдяки Згарбу

uSȯf¬`Bṁṡ

Спробуйте в Інтернеті!

Пояснення

       ṁṡ   Concatenate together the symmetric ranges of each coefficient
            (It is guaranteed that the integer roots lie in the range [-n..n],
                        where n is the coefficient with the largest magnitude)
 Sȯf        Find all the values in that range which
    ¬       are zero
     `B     when plugged through the polynomial
            (Base conversion acts as polynomial evaluation)
u           De-duplicate the roots

Ви можете зробити це ṁṡзамість того, oṡ►aякщо пізніше ви дедублюєте.
Згарб

@Zgarb Дуже приємно! Спасибі
H.PWiz

5

Хаскелл , 54 байти

f l|t<-sum$abs<$>l=[i|i<-[-t..t],foldl1((+).(i*))l==0]

Спробуйте в Інтернеті!

Груба сила та синтетичний поділ.

Unololfed з UniHaskell і-XUnicodeSyntax

import UniHaskell

roots     Num a  [a]  [a]
roots xs = [r | r  -bound  bound, foldl1 ((+)  (r ×)) xs  0]
             where bound = sum $ abs § xs

Черговий розчин, 44 байти

Кредит німі.

f l=[i|i<-[minBound..],foldl1((+).(i*))l==0]

Удачі з пробною допомогою в Інтернеті , оскільки це перевіряє кожне число в Intдіапазоні.


Ви можете переміщатися iнад [minBound..]і впустити всю tріч. Дзвінки fз явними Intсписками, наприклад f [1::Int,5,6]. Звичайно, це не закінчується в розумні строки.
німі

@nimi Чому це взагалі зупиниться? Хіба це не безмежно петля?
абсолютнолюдський

Ні, Boundedтипи зупиняються на maxBound, наприклад print [minBound::Bool ..].
німі

4

Python 2 + numpy, 95 93 91 103 93 91 82 байт

-2 байти завдяки овсам
дякує Луїсу Мендо за верхню / нижню межі коренів
-10 байт завдяки містеру Xcoder

from numpy import*
def f(r):s=sum(fabs(r));q=arange(-s,s);print q[polyval(r,q)==0]

Спробуйте в Інтернеті!



@LuisMendo так.
Прут

3
Нашим сьогоднішнім консенсусом здається, що програми повинні завжди припинятися, якщо в виклику не вказано інше.
Згарб

@Zgarb там, виправлено!
Прут

Використання numpy.polyvalекономить досить багато байтів
Містер Xcoder

4

Мова Вольфрама (Mathematica) , 50 47 42 25 27 байт

{}⋃Select[x/.Solve[#~FromDigits~x==0],IntegerQ]&

Спробуйте в Інтернеті!

Оновлення: використовуючи факт Луїса Мендо, виграли ще 3 байти

Pick[r=Range[s=-Tr@Abs@#,-s],#~FromDigits~r,0]&

Отримавши скат з межею, ми можемо зменшити ці 5 байтів за пропозицію @Не дерево:

Pick[r=Range[s=-#.#,-s],#~FromDigits~r,0]&

Опублікувавши це, ОП прокоментував дозволення "власних поліномів", тож ось 25-байтне рішення, яке приймає поліном як вхідний. Це працює, тому що за замовчуванням Mathematica множить многочлени на цілі числа, і будь-які раціональні корені відображаються у такій формі, m*x+bщо не дає відповідності шаблону.

Cases[Factor@#,b_+x:>-b]&

Як зазначав @alephalpha, це не вдасться в тому випадку, коли нуль є коренем, тож, щоб виправити, що ми можемо використовувати Optionalсимвол:

Cases[Factor@#,b_:0+x:>-b]&

Це добре аналізує Mathematica 11.0.1, але не працює і вимагає додаткового набору круглих дужок b_:0у версії 11.2. Це займає до 27 байт, а також ще два після версії 11.0.1. Схоже, тут було введено "виправлення"

Спробуйте в Інтернеті!


1
Я думаю, ви можете використовувати #.#замість Tr@Abs@#: це гірше пов'язаний, але менше байтів.
Не дерево

1
У коментарі ОП заявила, що ви можете використовувати рідний тип полінома вашої мови, якщо такий існує. Я не знаю добре Mathematica, але я думаю, що є такий ... Чи врятував би це байт?
Ніхто не показував моє справжнє ім’я


1
@alephalpha, виправлено.
Келлі Лоудер


3

Мова Вольфрама (Mathematica) , 33 26 31 байт

Виправлена ​​помилка, помічена Келлі Лоудер у коментарях.

x/.{}⋃Solve[#==0,x,Integers]&

Спробуйте в Інтернеті!

Попередні неправильні рішення:

Я щойно помітив, що для жодного цілого рішення вихід не визначений, а не порожній список; що дозволяє видалити кілька байт.

x/.Solve[#==0,x,Integers]&

Спробуйте в Інтернеті!

Тепер, якщо не існує цілого рішення, функція повертається x .

Раніше:

x/.Solve[#==0,x,Integers]/.x->{}&

Спробуйте в Інтернеті!


Це не вдається, як зазначено в даний час з 1,2,1, оскільки він повторює корінь, і ОП заявила, що вони повинні бути різними. Вам потрібно Unionце виправити.
Келлі Лоудер

@KellyLowder: Ах, це я пропустив. Але потім цього не було також у даних тестових випадках.
celtschk

@KellyLowder: я зараз це виправив. Якщо ви відмовилися через це, чи можете ви скасувати це?
четчек

@cellschk, так готово.
Келлі Лоудер

29 байт , використовуючи недокументовану функцію Solve: список змінних можна опустити.
Роман

3

R , 61 59 байт

Особлива подяка @mathmandan за вказівку на мій (неправильний) підхід можна врятувати і пограти в гольф!

function(p)(x=-(t=p[!!p][1]):t)[!outer(x,seq(p)-1,"^")%*%p]

Спробуйте в Інтернеті!

Приймає вхід як перелік коефіцієнтів у порядку зростання , тобто c(-1,0,1)представляє -1+0x+1x^2.

Використовуючи раціональну кореневу теорему, наступний підхід майже працює, на 47 байт:

function(p)(x=-p:p)[!outer(x,seq(p)-1,"^")%*%p]

Спробуйте в Інтернеті!

-p:pгенерує симетричний діапазон (з попередженням) , використовуючи тільки перший елемент p, a_0. Відповідно до теорії раціонального кореня , всі раціональні корені Pповинні мати форму, p/qде pділиться a_0і qділиться a_n(плюс чи мінус). Таким чином, використовуючи тільки a_0досить для |a_0|>0, як і для будь-якого q, |p/q|<=a_0. Однак коли a_0==0, як тоді, ділиться будь-яке ціле число0 , і, таким чином, це виходить з ладу.

Однак математичний вказівник вказує, що насправді в цьому випадку це означає, що існує постійний фактор, x^kякий можна визначити, і, якщо вважати, що kце максимальний, ми бачимо, що

P(x) = x^k(a_k + a_{k+1}x + ... a_n x^{n-k}) = x^k * Q(x)

Тоді ми застосовуємо теорему раціонального кореня до Q(x), і, як a_kгарантовано, це не максимальна нульова величина k, a_kзабезпечує акуратне обмеження для цілих коренів Q, а корені P- корені Qразом з нулем, тому у нас буде все ціле число корінняP , застосовуючи цей метод.

Це еквівалентно знаходженню першого ненульового коефіцієнта многочлена t=p[!!p][1]і використанні його замість наївного p[1]в якості меж. Більше того, оскільки діапазон -t:tзавжди містить нуль, застосовуючиP до цього діапазону все одно дасть нам нуль як корінь, якщо воно дійсно є.

неозорений:

function(polynom) {
 bound <- polynom[polynom != 0][1]             #first nonzero value of polynom
 range <- -bound:bound                         #generates [-bound, ..., bound]
 powers <- outer(range,seq_along(p) - 1, "^")  #matrix where each row is [n^0,n^1,n^2,...,n^deg(p)]
 polyVals <- powers %*% polynom                #value of the polynomial @ each point in range
 return(range[polyVals == 0])                  #filter for zeros and return
}


(Я думаю, ви можете використовувати maxабсолютні значення замість значень sum; це не змінить кількість байтів, але це повинно покращити продуктивність.) У будь-якому випадку, так, шкода, що коротша версія не працює a_0==0. Чи є якийсь короткий шлях у R для пошуку першого (із збільшенням потужності) ненульового коефіцієнта, і використовувати його замість цього? Це відповідатиме 0
розбиттю спершу

@mathmandan maxбув би більш ефективним, але до вашого другого пункту, оскільки мені не потрібно турбуватися про вихід, 0оскільки він генерується діапазоном -t:t(де tперший ненульовий коефіцієнт), він економить 2 байти!
Джузеппе

О, дуже приємно! (І прекрасне пояснення також.)
mathmandan

2

Желе , 8 байт

ASŒRḅ@Ðḟ

Спробуйте в Інтернеті! або як тестовий набір!

Як?

ASŒRḅ @ Ðḟ || Повна програма (монадичне посилання).

ЯК || Підсумовуйте абсолютні значення.
  ŒR || І створити симетричний інклюзивний діапазон від його негативного значення.
       Ðḟ || І відмовтеся від тих, які приносять велику цінність ...
     ḅ @ || При підключенні їх до многочлена (використовується базове перетворення).

Виходячи з відповіді Луїса . Альтернатива .


Щось мені не вистачає у прийнятті (дозволеному) зворотному порядку та виконанні Ær+.Ḟ?
Джонатан Аллан

Я трохи збентежений, оскільки відповідь Python з numpy також не робить цього, і я думаю, що я пропустив певний крайній випадок.
Джонатан Аллан

@JonathanAllan Як я очікував, ваші не вдається [1,2,3].
Містер Xcoder

"Якщо для даного рівняння немає рішення, то вихід не визначений"
Джонатан Аллан,

@JonathanAllan Але це дійсно НЕ в змозі в протягом [10,-42,8], НЕ так?
Містер Xcoder

2

Октава , 59 49 байт

@(p)(x=-(t=p(~~p)(end)):sign(t):t)(!polyval(p,x))

Спробуйте в Інтернеті!

Це порт мого R відповіді . Єдина відмінність полягає в тому, що я повинен явно використовувати sign(t)і endгенерувати діапазон, і що він polyvalповинен обчислити поліном.

Приймає введення як векторний коефіцієнт у порядку зменшення.



2

C (gcc) , 127 126 123 байт

x,X,j,m,p;f(A,l)int*A;{for(m=j=0;j<l;m+=abs(A[j++]));for(x=~m;X=x++<m;p||printf("%d,",x))for(p=j=0;j<l;X*=x)p+=A[l-++j]*X;}

Спробуйте в Інтернеті!


Пояснення

C (gcc) , 517 байт

x,X,j,m,p;                      // global integer variables
f(A,l)int*A;{                   // define function, takes in integer array pointer and length
 for(m=j=0;j<l;m+=abs(A[j++])); // loop through array, sum up absolute values
  for(x=~m;X=x++<m;             // loop through all values x in [-m, m], prime X
   p||printf("%d,",x))          // at loop's end, print x value if polynomial value is zero
    for(p=j=0;j<l;X*=x)         // loop through coefficients
     p+=A[l-++j]*X;}            // build polynomial

Спробуйте в Інтернеті!


l+~j++можна пограти в гольф доl-++j
Кевін Круїссен

@KevinCruijssen Дякую велике
Джонатан Фрех

@ceilingcat Дякую
Джонатан Фрех

1

Ява 8, 141 140 bytes

a->{int l=a.length,s=0,i,r,f,p;for(int n:a)s+=n<0?-n:n;for(r=~s;r++<s;System.out.print(p==0?r+",":""))for(p=i=0,f=1;i<l;f*=r)p+=a[l-++i]*f;}

Натхненний @Rod's Python 2 answer (his 82 bytes version).

Fun challenge! I certainly learned a lot of it when investigating about polynomials and seeing how some others here have done it.

Пояснення:

Спробуйте в Інтернеті.

a->{                   // Method with integer-array parameter and no return-type
  int l=a.length,      //  The length of the input-array
      s=0,             //  Sum-integer, starting at 0
      i,               //  Index integer
      r,               //  Range-integer
      f,               //  Factor-integer
      p;               //  Polynomial-integer
  for(int n:a)         //  Loop over the input-array
    s+=n<0?-n:n;       //   And sum their absolute values
  for(r=~s;r++<s;      //  Loop `r` from `-s` up to `s` (inclusive) (where `s` is the sum)
      System.out.print(p==0?r+",":""))
                       //    After every iteration: print the current `r` if `p` is 0
    for(p=i=0,         //   Reset `p` to 0
        f=1;           //   and `f` to 1
        i<l;           //   Loop over the input-array again, this time with index (`i`)
        f*=r)          //     After every iteration: multiply `f` with the current `r`
      p+=              //    Sum the Polynomial-integer `p` with:
         a[l-++i]      //     The value of the input at index `l-i-1`,
                 *f;}  //     multiplied with the current factor `f`



0

JavaScript (ES6), 97 bytes

a=>[...Array((n=Math.max(...a.map(Math.abs)))-~n)].map(_=>n--).filter(i=>!a.reduce((x,y)=>x*i+y))

Takes coefficients in decreasing order of power and outputs results in descending order.



Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.