Регистрация не е нужна, освен при създаване на тема в "Задача на седмицата".

Softuniada problem 8

Softuniada problem 8

Мнениеот Гост » 09 Апр 2021, 21:30

softuniada p8.png
softuniada p8.png (50 KiB) Прегледано 778 пъти
On a rectangular chess board with X rows and Y columns, N rooks should be placed in such a way, so that each of them is attacked by at most 1 other rook. One rook is attacked by another rook, if they are placed on the same row, or on the same column, and there are no other rooks between them.
Write a program, which finds the count of all possible ways that these N rooks can be placed on the X / Y chess board, so that they cover the conditions specified above. Due to the fact, that the answer may be a very big number, always print the remainder of the division of the actual count with 1,000,001.

Input
The input consists of 3 input lines:
• On the first line you will receive X – the rows of the chessboard
• On the second line you will receive Y – the columns of the chessboard
• On the third line you will receive N – the count of rooks that should be placed on the chessboard

Output
The output should consist of a single line, containing the remainder of the division of the desired count, with 1,000,001.
Constraints
• X, Y and N will be integers in range [1, 100].
• Allowed working time / memory: to be defined.

Ако може решението да е на C#. Или ако не можете да решите цялата задача, поне дайте идеи за решение.
Гост
 

Re: Softuniada problem 8

Мнениеот peyo » 13 Юни 2021, 15:14

Гост написа:
softuniada p8.png
On a rectangular chess board with X rows and Y columns, N rooks should be placed in such a way, so that each of them is attacked by at most 1 other rook. One rook is attacked by another rook, if they are placed on the same row, or on the same column, and there are no other rooks between them.
Write a program, which finds the count of all possible ways that these N rooks can be placed on the X / Y chess board, so that they cover the conditions specified above. Due to the fact, that the answer may be a very big number, always print the remainder of the division of the actual count with 1,000,001.

Input
The input consists of 3 input lines:
• On the first line you will receive X – the rows of the chessboard
• On the second line you will receive Y – the columns of the chessboard
• On the third line you will receive N – the count of rooks that should be placed on the chessboard

Output
The output should consist of a single line, containing the remainder of the division of the desired count, with 1,000,001.
Constraints
• X, Y and N will be integers in range [1, 100].
• Allowed working time / memory: to be defined.

Ако може решението да е на C#. Или ако не можете да решите цялата задача, поне дайте идеи за решение.



Това е много интересна задача и ми отне доста време докато обмислях различни решения, но и аз пък не бързах. В началото си мислех, че може би има директна формула която да даде резултата. Още не съм намерил такава. След това реших, че сигурно има хубава рекурсивна функция която в комбинация с Dynamic programming и @lru_cache ще свърши работа и такова наистина се оказа решението което представям тук.

Първо написах програма която по възможно най-brute force намира отговора за малките числа. няма да я давам тук, но сложноста и е нещо като $O(XY2^{XY})$. Най-големите стойности за които я пуснах бяха X=5, Y=5, N=7 и върна резултат след 30 секунди. Но ми даде тестови данни с които да тествам бързата функция.

Бързата функция е:

$f(x,y,n) = \frac{x(x-1)}{2}f(x-2,y-1,n-2) + f(x,y-1,n) + x(y-1)f(x-1,y-2,n-2) + xf(x-1,y-1,n-1)$

Как съставих тази функция? Идеята е следната, например първата част $\frac{x(x-1)}{2}f(x-2,y-1,n-2)$ казва слагаме един топ на първия ред на някоя $x$ позиция, слагаме 2-ри топ на същия ред на някоя от останалите $x-1$ позиции , умножаваме тези две числа и ги делим на 2 и това са броя на комбинациите които можем да направим от 2 топа на един ред и след това от дъската изключваме този ред и тези 2 колони, защото не можем на тях да слагаме повече топове и пускаме фунцкията за останалите $f(x-2,y-1,n-2)$. Останалите части подобна логика.

Програмата която я имплементира е:

Код: Избери целия код
   from functools import lru_cache
   @lru_cache(maxsize = None)
   def f(x,y,n):
      if x<=0 or y<=0 or n==0:
         return 0
      if n == 1:
         return x*y
      if n == 2:
         return x*y*(x*y-1)//2
      return x*(x-1)*f(x-2,y-1,n-2)//2 + f(x,y-1,n) + x*(y-1)*f(x-1,y-2,n-2) + x*f(x-1,y-1,n-1)


Да я тестваме с примерите:

In [102]: f(4,6,2)
Out[102]: 276

In [103]: f(9,6,10)
Out[103]: 340200

In [104]: f(99,98,100)
Out[104]: 47716292659965237869320265557301253064912097095671321541359391563983349799122665140807253019080511522871444179307786903481024995730822967772318401645588881634937699689344614655096884769587200000000000000000000000

In [105]: f(99,98,100) % 1000001
Out[105]: 951454

Каква е сложността на бързата функция нямам представа, но малко експериментални данни до X=400, Y=400 приличат на $O(X^3)$
peyo
Математик
 
Мнения: 1759
Регистриран на: 16 Мар 2019, 09:35
Местоположение: София
Рейтинг: 656


Назад към C#, Java



Кой е на линия

Регистрирани потребители: Google [Bot]

Форум за математика(архив)