рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╢реБрднрдХрд╛рдордирд╛рдПрдБ Habrahabr!
рдореИрдВрдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╣рд╛рд╕реНрдХреЗрд▓ рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рдФрд░ рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рдорд╣рд╛рд░рдд рд╣рд╛рд╕рд┐рд▓ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВрдиреЗ рдереЛрдбрд╝рд╛ рд╕рдВрдЪрд┐рдд рдЕрдиреБрднрд╡ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдмреЗрд╢рдХ, рд╣рд╛рд╕реНрдХреЗрд▓ рдХрд╛ рдЬреНрдЮрд╛рди
рдбрд╛рд░реНрдХрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрд╕ рд╕реНрддрд░ рдкрд░ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдиреАрдЪреЗ рд╡рд░реНрдгрд┐рдд рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рд╢реБрд░реБрдЖрддреА рд▓реЛрдЧреЛрдВ рдкрд░ рдЕрдзрд┐рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдиреБрднрд╡реА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╢рд╛рдпрдж рдЗрд╕реЗ рдареАрдХ рдХрд░ рджреЗрдВрдЧреЗ рдФрд░ рдЖрдкрдХреЛ рдмрддрд╛рдПрдВрдЧреЗ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдмреЗрд╣рддрд░ рдХрд░рдирд╛ рд╣реИред рдпрд╣ рдХреЗрд╡рд▓ рд╣рдмреНрд░рд╣рд╛рдмреНрд░ рдкрд░ рдореЗрд░рд╛ рдкрд╣рд▓рд╛ рд▓реЗрдЦ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдореЗрд░рд╛ рдкрд╣рд▓рд╛ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдЬреЛ рдореИрдВрдиреЗ рдХрднреА рд▓рд┐рдЦрд╛ рд╣реИред
рдЯрд╛рд╕реНрдХ 1
N рдЬрд┐рд▓реЛрдВ рд╡рд╛рд▓реЗ рд╢рд╣рд░ рдореЗрдВ, рд╕реАрдорд╛ рд╢реБрд▓реНрдХ рдмрд┐рдВрджреБ рдмрдирд╛рдП рдЬрд╛рдиреЗ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рд╢рд╣рд░ рдХреЗ рд╕рдмрд╕реЗ рд╡реНрдпрд╕реНрдд рдЗрд▓рд╛рдХреЛрдВ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рднрд░рд╛ рд╣реБрдЖ рд╡рд╣ рдХреНрд╖реЗрддреНрд░ рд╣реИ рдЬрд┐рд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрдк рдЧреБрдЬрд░рддреЗ рд╣реИрдВ рдпрджрд┐ рдЖрдк рд╢рд╣рд░ рдП рдХреЗ рднрд╛рдЧ рдмреА рд╕реЗ рднрд╛рдЧ рдореЗрдВ рдЬрд╛рддреЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рддред рдЕрдЧрд░ рдХреЛрдИ рдЪрдХреНрдХрд░ рдирд╣реАрдВ рд╣реИред рдЕрдЧрд░ рд╣рдо рд╢рд╣рд░ рдХреЛ рдПрдХ рдЧреНрд░рд╛рдл рдХреЗ рд░реВрдк рдореЗрдВ рдФрд░ рдиреЛрдбреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рд░реНрдЧ рдХреЗ рд▓рд┐рдП рд╕рднреА "рдЕрдбрд╝рдЪрдиреЛрдВ" (= рдЕрдбрд╝рдЪрдиреЛрдВ рдХреЛ рдпрд╛ "рд╕реБрдИ рдХреА рдЖрдВрдЦ") рднреА рдХрд╣рддреЗ рд╣реИрдВред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдШреЛрд╖рдгрд╛рдПрдБ рджреА рдЧрдИ рд╣реИрдВ:
type District = Integer type NumOfDistricts = Integer type Route = (District, District) newtype CityMap = CM (NumOfDistricts, [Route])
рдЕрдВрдд рдореЗрдВ, рдлрд╝рдВрдХреНрд╢рди рдЪрд╛рд▓реВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:
bottlenecks :: CityMap -> District -> District -> [Bottleneck]
рдпрд╛рдиреА рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реБрдП CityMap рдФрд░ рджреЛ рдХреНрд╖реЗрддреНрд░ (рд╢реБрд░реБрдЖрдд рдФрд░ рдЕрдВрдд), рд╣рдореЗрдВ рд╕рднреА рдиреЛрдбреНрд╕ рдХреА рдПрдХ рд╕рд░рдгреА рдорд┐рд▓рддреА рд╣реИ рдЬрд┐рд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рдореЗрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдЕрдЧрд░ рд╣рдо рдПрдХ рдкрдВрдХ рд╕реЗ рджреВрд╕рд░реЗ рдореЗрдВ рдЬрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
рдореИрдВ рдЖрдкрдХреЛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗрддрд╛ рд╣реВрдВред рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╢рд╣рд░ рд╣реИрдВ
рд╢рд╣рд░ = рд╕реАрдПрдо (6, [(2,3), (1,2), (3,1), (4,3), (4,6), (5,6), (5,3)])

рддрдм рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓ рдХрд░реЗрдВ
bottlenecks city 1 6
рдиреЛрдб рд╕рдВрдЦреНрдпрд╛ 3 (рдПрдХ рдиреЛрдб рд╕реЗ рдорд┐рд▓рдХрд░ рдПрдХ рд╕рд░рдгреА) рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рд╢реБрд░реБрдЖрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдЬреЛ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдиреЛрдб рдХреЗ рд╕рднреА рдкрдбрд╝реЛрд╕рд┐рдпреЛрдВ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реИред
neighbours :: CityMap -> District -> [District]
рдЪреВрдВрдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд░реВрдЯ рддрддреНрд╡ рдореЗрдВ рдХреЗрд╡рд▓ рджреЛ рддрддреНрд╡ рд╣реЛрддреЗ рд╣реИрдВ, рд╣рдо рдмрд╕ рдпрд╣ рдЬрд╛рдВрдЪ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЬреЛрдбрд╝реА рдХреЗ рддрддреНрд╡реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ (рдкреА, рдХреНрдпреВ) рд╡рд╛рдВрдЫрд┐рдд (рдмреА) рддрддреНрд╡ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдпрджрд┐ b, p рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ, рддреЛ q рдФрд░ рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд рдЬреЛрдбрд╝реЗрдВред рдЖрдк рдЗрд╕рдХреЗ рд▓рд┐рдП mapMaybe рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
neighbours (CM (_,rs)) b = mapMaybe neighbour rs where neighbour (p,q) | b == p = Just q | b == q = Just p | otherwise = Nothing
рдкрд░реАрдХреНрд╖рдг:
*Main Data.List> neighbours city 3
[2,1,4,5]
рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ! рдЕрдм рдЬрдм рдЖрдк рдХрд┐рд╕реА рднреА рдиреЛрдб рдХреЗ рдкрдбрд╝реЛрд╕рд┐рдпреЛрдВ рдХреЛ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдХрд┐рд╕реА рднреА рджреЛ рдмрд┐рдВрджреБрдУрдВ рдХреЗ рдмреАрдЪ рдХрд╛ рд░рд╛рд╕реНрддрд╛ рдЦреЛрдЬрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред рдпрд╛ рдмрд▓реНрдХрд┐, рди рдХреЗрд╡рд▓ рдПрдХ рдорд╛рд░реНрдЧ, рдмрд▓реНрдХрд┐ рд╕рднреА рд╕рдВрднрд╡ рдкрде:
paths :: CityMap -> District -> District -> [Path]
рд╣рдореЗрдВ рдЙрд╕ рдиреЛрдб рдХреЛ рдпрд╛рдж рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рд╣рд░ рдЪрд░рдг рдХреЛ рдирд╣реАрдВ рднреВрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд┐рд╕реЗ рд╣рдо рдкрд╣рд▓реЗ рд╣реА рджреЗрдЦ рдЪреБрдХреЗ рд╣реИрдВ (рдЕрдиреНрдпрдерд╛ рд╣рдо рд╕рд░реНрдХрд▓ рдореЗрдВ рдЕрдВрддрд╣реАрди рд░реВрдк рд╕реЗ рдЪрд▓реЗрдВрдЧреЗ)ред рд╢реБрд░реВ рд╕реЗ рд▓рдХреНрд╖реНрдп рддрдХ рдХреЗ рд░рд╛рд╕реНрддреЗ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо:
1. рдпрджрд┐ start == рд▓рдХреНрд╖реНрдп рд╣реИ, рддреЛ рд╡рд╛рдкрд╕ рд▓реМрдЯреЗрдВ [[рдкреНрд░рд╛рд░рдВрдн]]
2. рдпрджрд┐ рд╢реБрд░реВ рдХреА рдЧрдИ рдиреЛрдбреНрд╕ (= рд╡рд┐рдЬрд╝рд┐рдЯ рдХреА рдЧрдИ) рдХреА рд╕рд░рдгреА рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ, рддреЛ рдкрдбрд╝реЛрд╕рд┐рдпреЛрдВ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ (= рдЕрдЧрд▓реЗ) рдХреЗ рд▓рд┐рдП рд╣рдо рдЗрд╕ рдкрдбрд╝реЛрд╕реА рд╕реЗ рд▓рдХреНрд╖реНрдп рддрдХ рдХрд╛ рд░рд╛рд╕реНрддрд╛ рддрд▓рд╛рд╢рддреЗ рд╣реИрдВред
3. рдЕрдиреНрдпрдерд╛ рд╡рд╛рдкрд╕ рд▓реМрдЯреЗрдВ [] (рдпрджрд┐ рд╣рдо рдкрд╣рд▓реЗ рд╣реА рд╢реБрд░реВ рд╣реЛ рдЪреБрдХреЗ рд╣реИрдВ)
рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрде рдлрд╝рдВрдХреНрд╢рди рд╡рд┐рдЬрд╝рд┐рдЯ рдХрд┐рдП рдЧрдП рдиреЛрдбреНрд╕ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдкрд░ "рд╕реЗрд╡" рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕реЗ рдкрдереЛрдВ рдХреЗ рдЙрдк-рдХрд╛рд░реНрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
paths :: CityMap -> District-> District -> [Path] paths cm start goal = paths' [] cm start goal where paths' visited cm start goal | start == goal = [[start]] | start `notElem` visited = [start:rest | next <- neighbours cm start, rest <- paths' (start:visited) cm next goal] | otherwise = []
рдкрд░реАрдХреНрд╖рдг:
*Main Data.List> paths city 1 2
[[1,2],[1,3,2]]
рдП рд╕реЗ рдмреА рддрдХ рд╕рднреА рд╕рдВрднрд╡ рдкрде рд╣реЛрдиреЗ рдХреЗ рдХрд╛рд░рдг, рдПрдХ рдЕрдбрд╝рдЪрди рдЦреЛрдЬрдиреЗ рдореЗрдВ рдХрд╛рдлреА рдЖрд╕рд╛рди рд╣реИ - рдпрд╣ рдиреЛрдб рд╣реИ рдЬреЛ рд╕рднреА рддрд░реАрдХреЛрдВ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдиреЛрдбреНрд╕ рдП рдФрд░ рдмреА рднреА рд╕рднреА рд░рд╛рд╕реНрддреЛрдВ рдореЗрдВ рдореМрдЬреВрдж рд╣реЛрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ рддреБрд░рдВрдд рд╕рдВрднрд╡ рд╕рдорд╛рдзрд╛рди рд╕реЗ рдмрд╛рд╣рд░ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:
[1..n] \\ [start, goal]
рд╕рднреА рд░рд╛рд╕реНрддреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреНрд░рддрд┐рдЪреНрдЫреЗрдж рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рдХреЗрд╡рд▓ рдЙрди рддрддреНрд╡реЛрдВ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдЬреЛ рджреЛрдиреЛрдВ рд╕реЗрдЯреЛрдВ рдореЗрдВ рдкрд╛рдП рдЬрд╛рддреЗ рд╣реИрдВред рдпрд╛рдиреА рдЖрдкрдХреЛ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рд╕рдорд╛рдзрд╛рдиреЛрдВ рдФрд░ рд╕реЗрдЯ рдкрдереЛрдВ рдХреЗ рдкрд╣рд▓реЗ рддрддреНрд╡ рдХреЗ рд╕реЗрдЯ рдкрд░ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдлрд┐рд░ рджреВрд╕рд░реЗ рддрддреНрд╡ рдХреЗ рдЙрддреНрддрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдЖрджрд┐ред рдЙрддреНрддрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
((((([1..n] \\ [start, goal]) intersect paths[0]) intersect paths[1]) intersect paths[2]) intersect...)
рдлрд┐рд░, рдмрд╛рдзрд╛рдУрдВ рдХреЛ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
bottlenecks :: CityMap -> District -> District -> [Bottleneck] bottlenecks cm@(CM (n,_)) start goal = foldl intersect ([1..n] \\ [start, goal]) $ (paths cm start goal)
Data.Maybe (mapMaybe рдХреЗ рд▓рд┐рдП) рдФрд░ Data.List (рдкреНрд░рддрд┐рдЪреНрдЫреЗрдж рдХреЗ рд▓рд┐рдП) рдореЙрдбреНрдпреВрд▓ рдЖрдпрд╛рдд рдХрд░рдирд╛ рдпрд╛рдж рд░рдЦреЗрдВред
рдЯрд╛рд╕реНрдХ реи
рд╣рдо рдПрдХ рд╕рдорд╛рди рд╕рдорд╕реНрдпрд╛ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рддреН,
Erd├╢s рд╕рдВрдЦреНрдпрд╛ рдХреА рд╕рдорд╕реНрдпрд╛ред рдореИрдВ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ: рдЧрдгрд┐рддрдЬреНрдЮ
рдкреЙрд▓ рдПрд░реНрджреЛ рдХреЗ рд╕рд╛рде рдПрдХ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ рд▓реЗрдЦ рд▓рд┐рдЦрдиреЗ рд╡рд╛рд▓реЗ рд╕рднреА рдХреЛ рдирдВрдмрд░ 1 рдорд┐рд▓рддрд╛ рд╣реИ, рдЙрди рд╕рднреА рдиреЗ рдЬреЛ рд╕рд╣-рд▓реЗрдЦрдХ рдкреЙрд▓ рдПрд░реНрджреЛ рдХреЗ рд╕рд╛рде рдПрдХ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ рд▓реЗрдЦ рд▓рд┐рдЦрд╛ рдерд╛ (рд▓реЗрдХрд┐рди рдЙрдирдХреЗ рд╕рд╛рде рдирд╣реАрдВ) рдирдВрдмрд░ 2 рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рдЖрджрд┐ред рдЕрд░реНрдерд╛рдд, Erd├╢s рдирдВрдмрд░ n рд╡рд╛рд▓реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд╕рд╣-рд▓реЗрдЦрдХ рдХреЗ рдкрд╛рд╕ Erd├╢s рдирдВрдмрд░ n + 1 рд╣реИред рдХрд╛рд░реНрдп рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд▓рд┐рдП рдпрд╣ рд╕рдВрдЦреНрдпрд╛ рдвреВрдВрдврдирд╛ рд╣реИ (рдпрджрд┐ рдЗрд╕ рд╡реНрдпрдХреНрддрд┐ рдФрд░ рдПрд░реНрджреЛ рдХреЗ рдмреАрдЪ рд╕рдВрдмрдВрдз рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдирдВрдмрд░ -1 рдкреНрд░рд┐рдВрдЯ рдХрд░реЗрдВ)ред рддреЛ, рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЙрди рдбреЗрдЯрд╛ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рдирдХреЗ рд╕рд╛рде рд╣рдо рдХрд╛рдо рдХрд░реЗрдВрдЧреЗ - рдпреЗ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ рд╣реИрдВ (рдПрдХ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ рдореЗрдВ рдПрдХ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдФрд░ рдПрдХ рдЙрдкрдирд╛рдо рд╣реЛрддрд╛ рд╣реИ), рд╡реЗ рд▓реЗрдЦрдХ рднреА рд╣реИрдВ, рд╕рд╛рде рд╣реА рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдХрд╛ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдЬрд┐рд╕рдореЗрдВ рд▓реЗрдЦ рдХрд╛ рд╢реАрд░реНрд╖рдХ (рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ рдХрд╛рд░реНрдп) рдФрд░ рд▓реЗрдЦрдХреЛрдВ рдХреЗ рдирд╛рдо рд╣реИрдВ рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рдЗрд╕реЗ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд┐рдпрд╛ рд╣реИ ред рд╣рдо рдЙрд╕ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рднреА рдШреЛрд╖рд┐рдд рдХрд░реЗрдВрдЧреЗ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдХрд░реЗрдВрдЧреЗ:
type ErdosNumber = Int data Scientist = Sc Initial SurName type Initial = Char type SurName = String type Author = Scientist newtype Database = Db [([Author],PaperTitle)] type PaperTitle = String type Path = [Author] db = Db [([Sc 'M' "Smith",Sc 'G' "Martin",Sc 'P' "Erdos"],"Newtonian Forms of Prime Factors"), ([Sc 'P' "Erdos",Sc 'W' "Reisig"],"Stuttering in Petri Nets"), ([Sc 'M' "Smith",Sc 'X' "Chen"],"First Order Derivates in Structured Programming"), ([Sc 'T' "Jablonski",Sc 'Z' "Hsueh"],"Selfstabilizing Data Structures"), ([Sc 'X' "Chen",Sc 'L' "Li"],"Prime Numbers and Beyond")]
рдЖрдЗрдП рдкрд┐рдЫрд▓реЗ рдХрд╛рд░реНрдп рдХреЗ рд░реВрдк рдореЗрдВ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдХрд░ рдЬреЛ рд╕рднреА рдкрдбрд╝реЛрд╕рд┐рдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ (рдпрд╛рдиреА рдЬреЛ рдЗрд╕ рд▓реЗрдЦрдХ рдХреЗ рд╕реАрдзреЗ рд╕рдВрдкрд░реНрдХ рдореЗрдВ рд╣реИрдВ):
neighbours :: Database -> Author -> [Author]
рдкрд┐рдЫрд▓реЗ рдХрд╛рд░реНрдп рдХреЗ рд╡рд┐рдкрд░реАрдд, рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рддрддреНрд╡ рдореЗрдВ рджреЛ рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓реЗрдЦрдХ рд╢рд╛рдорд┐рд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдкрдореЗрдм рдлрд╝рдВрдХреНрд╢рди рдЕрдкрд░рд┐рд╣рд╛рд░реНрдп рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рдЖрдЗрдЯрдо ([рд▓реЗрдЦрдХ], рдкреЗрдкрд░рдЯреЗрд▓) рдХреЗ рд▓рд┐рдП рд╣рдо рдЬрд╛рдБрдЪреЗрдВрдЧреЗ рдХрд┐ рдХреНрдпрд╛ рд▓реЗрдЦрдХ, рдЬрд┐рдирдХреЗ рдкрдбрд╝реЛрд╕реА рд╣рдо рдЦреЛрдЬрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, [рд▓реЗрдЦрдХ] рд╕рд░рдгреА рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддреЗ рд╣реИрдВ, рдпрджрд┐ рдРрд╕рд╛ рд╣реИ, рддреЛ рдкреВрд░реЗ [рд▓реЗрдЦрдХ] рд╕рд░рдгреА рдХреЛ рд▓реЗ рд▓реЗрдВ, рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдЕрдЧрд▓реЗ рддрддреНрд╡ рдкрд░ рдЬрд╛рдПрдВ рдбреЗрдЯрд╛рдмреЗрд╕ред рдЕрдВрдд рдореЗрдВ, рдЙрд╕ рд▓реЗрдЦрдХ рдХрд╛ рдирд╛рдо рд╣рдЯрд╛рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛ рдЬрд┐рд╕реЗ рд╣рдо рдкрд░рд┐рдгрд╛рдореА рд╕реВрдЪреА рд╕реЗ рдвреВрдВрдв рд░рд╣реЗ рдереЗ (рд╣рдо рдЙрд╕рдХреЗ рдкрдбрд╝реЛрд╕рд┐рдпреЛрдВ рдХреА рддрд▓рд╛рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЙрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ):
neighbours :: Database -> Author -> [Author] neighbours (Db []) _ = [] neighbours (Db ((a,_):xs)) (Sc is) = filter (/= (Sc is)) ((neighbour a) ++ (neighbours (Db xs) (Sc is))) where neighbour a | (Sc is) `elem` a = a | otherwise = []
рдпрд╣ рдШреЛрд╖рд┐рдд рдХрд░рдирд╛ рди рднреВрд▓реЗрдВ рдХрд┐ рд╣рдо рдЕрдкрдиреЗ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХреИрд╕реЗ рдХрд░реЗрдВрдЧреЗ:
instance Eq Scientist where (Sc i1 s1) == (Sc i2 s2) = (i1 == i2) && (s1 == s2)
рдЕрдм рд╣рдо "рдкреНрд░рд╛рд░рдВрдн" рдХреЗ рд▓реЗрдЦрдХ рд╕реЗ рд▓реЗрдХрд░ рд╡реИрдЬреНрдЮрд╛рдирд┐рдХ (Sc 'P' "Erdos") рддрдХ рд╕рднреА рд╕рдВрднрд╡ рддрд░реАрдХреЛрдВ рдХреА рддрд▓рд╛рд╢ рдХрд░реЗрдВрдЧреЗред рдкрде рдлрд╝рдВрдХреНрд╢рди рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдХреЛрдИ рднрд┐рдиреНрди рдирд╣реАрдВ рд╣реИ рдЬреЛ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рд▓рд┐рдЦрд╛ рдерд╛:
paths :: Database -> Author -> [Path] paths db start = paths' [] db start where paths' visited db start | start == (Sc 'P' "Erdos") = [[start]] | start `notElem` visited = [start:rest | next <- neighbours db start, rest <- paths' (start:visited) db next] | otherwise = []
рд▓реЗрдЦрдХ рд╕реЗ Erd├╢s рддрдХ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рд░рд╛рд╕реНрддреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реЛрдиреЗ рд╕реЗ, рдЖрдк рд▓рдВрдмрд╛рдИ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрде рдХреЛ рдЙрд╕рдХреА рд▓рдВрдмрд╛рдИ рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ (рдпрд╛рдиреА, рд╣рдореЗрдВ рдПрдХ рдРрд╕рд╛ рд╕рд░рдгреА рдорд┐рд▓рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдкрде рдХреА рд▓рдВрдмрд╛рдИ рд╣реЛрддреА рд╣реИ)ред рдкрд░рд┐рдгрд╛рдореА рд╕рд░рдгреА рд╕реЗ, рдиреНрдпреВрдирддрдо рд╕рдВрдЦреНрдпрд╛ (= рд╕рдмрд╕реЗ рдЫреЛрдЯрд╛ рдкрде) рдЪреБрдиреЗрдВ рдФрд░ рдЗрд╕ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕реЗ рдПрдХ рдШрдЯрд╛рдПрдВ, рдХреНрдпреЛрдВрдХрд┐ Erd├╢s рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реНрд╡рдпрдВ 0. рд╣реИ рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рднреВрд▓ рдЬрд╛рдПрдВ, рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рд░рд╛рд╕реНрддрд╛ рд╣реИ рдЬреЛ Erd├╢s рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ (рдпрджрд┐ рдирд╣реАрдВ, рддреЛ -1 рд╡рд╛рдкрд╕ рдХрд░реЗрдВ):
erdosNum :: Database -> Scientist -> ErdosNumber erdosNum db sc | length (paths db sc) == 0 = (-1) | otherwise = (-) (minimum (map length (paths db sc))) 1
рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЗрдВ рдЧреБрдб рд▓рдХ!