import Data.List {- Задача. Есть некоторое количество участников, которых нужно разбить на две равные команды.-} участников = ["Антон", "Маша", "Дима", "Юра", "Андрей", "Инна", "Олег", "Света"] {- При этом некоторые пары участников хотят обязательно быть в одной команде, а некоторые - обязательно в разных. -} будутВместе = [("Антон", "Маша"), ("Олег", "Света")] будутПорознь = [("Андрей", "Инна"), ("Олег", "Юра")] {- Нужно найти все подходящие варианты разбиений. -} main = показать $ подходящие `из` всехРазбиений участников {- Немножко русских синонимов для стандартных функций. -} размер = length будетВ = (:) infixr 5 `будетВ` но = flip ($) infixl 6 `но` из = filter в = elem иначе = otherwise пополам = (`quot` 2) когдаИ True True = True когдаИ False False = True когдаИ _ _ = False наоборот = not одно `либо` другое = одно `когдаИ` другое `но` наоборот все = all черезЗапятую = intercalate ", " показать = mapM_ $ \(первые, вторые) -> putStrLn $ черезЗапятую первые ++ " и их оппоненты " ++ черезЗапятую вторые отобрать = filter {- Ну и собственно простой переборный алгоритм. -} ктоХочет вместе команде = все (\(первый, второй) -> (первый `в` команде) `когдаИ` (второй `в` команде)) вместе ктоНеХочет вместе команде = все (\(первый, второй) -> (первый `в` команде) `либо` (второй `в` команде)) вместе размерКоманды = размер участников `но` пополам всехРазбиений = безДублей . разбиения [] [] where безДублей [] = [] безДублей (вотЭта:пропустить:остальных) = вотЭта `будетВ` остальных `но` безДублей разбиения первой второй другие | размер первой == размерКоманды = [(первой, второй ++ другие)] | размер второй == размерКоманды = [(первой ++ другие, второй)] | иначе = let новый : остальные = другие in. разбиения (новый `будетВ` первой) второй остальные ++ разбиения первой (новый `будетВ` второй) остальные подходящие (вПервой, воВторой) = ктоХочет будутВместе вПервой && ктоНеХочет будутПорознь вПервой