Երկուական որոնում պատասխանի վրա – Ծառերը հնարավորինս նոսր տնկել
Տրված է n տեղ, որտեղ կարելի է տնկել ծառեր։ Ցանկանում եք դրանք տնկել այնպես, որ ծառերը հնարավորինս նոսր լինեն և մի քանի տարի անց իրար չխանգարեն։ Այդ տեղերի կոորդինատները տրված են որպես ամբողջ թվեր :
Ձեր խնդիրն է պարզել այն նվազագույն հեռավորությունը, որը թույլ կտա t ծառ տնկել, բայց ծառերը կլինեն հնարավորինս նոսր։
Մուտք
Մուտքի առաջին տողում տրված են երկու ամբողջ թվեր n (1 ≤ n ≤ 100 000) — տեղերի քանակը և t (2 ≤ t ≤ n) — ծառերի այն քանակը, որը պետք է տնկել:
Հաջորդ տողում տրված են n տարբեր ամբողջ թվեր (0 ≤ ≤ ), որոնք ցույց են տալիս այն կոորդինատները, որտեղ կարելի է ծառ տնկել:
Ելք
Ծրագիրը պետք է տպի d նվազագույն հեռավորությունը, որի դեպքում ծառերը հնարավորինս նոսր տնկված կլինեն։
Օրինակներ
Մուտք
Ելք
5 3
1
2
8
4
9
3
Բացատրություն
Հնարավոր է օրինակ ծառերը տնկել 1, 4 և 9 կոորդինատներում, որի դեպքում 1 և 4 կոորդինատների միջև հեռավորությունը կլինի 3։ Սա էլ կլինի նվազագույնը, եթե ծառերը տնկենք հնարավորինս նոսր։
Ուղեցույց
Մենք կարող ենք լուծել այս առաջադրանքը պատասխանի վրա երկուական որոնում (Binary Search) իրականացնելով և ամեն քայլին ստուգենք, թե արդյոք հնարավոր է տնկել ծառերը տրված նվազագույն հեռավորությամբ։ Նկատենք, որ երկուական որոնում կիրառելու համար հարկավոր է, որ հետևյալ պայմանները կատարվեն.
Պետք է կարողանանք ստուգել, թե արդյոք թեկնածու պատասխանը բավարարում է առաջադրանքի պահանջնրին (այստեղ — մեզ անհրաժեշտ է ստուգել, թե արդյոք կարելի է տնկել ծառերը այնպես, որ դրանք լինեն իրարից նվազագույնը d հեռավորության վրա)։
Ստուգող ֆունկցիա def check(x):-ը պետք է վերադարձնի True, եթե հնարավոր է տվյալ թեկնածու պատասխանի դեպքում բավարարել խնդրի պահանջը, և False հակառակ դեպքում։
Տարբեր արժեքների (երկուական որոնման ընթացքում) ստուգման արդյունքներն ունեն երկու հիմնական կառուցվածք.
False False False True True (Հնարավոր չէ առաջին մի քանի թվի համար և հետո հնարավոր է մնացած ավելի մեծ թվերի համար)։ Այս դեպքում մենք ման փնտրում ենք առաջին True արժեքը՝ ամենափոքր արժեքը, որի դեպքում խնդրի պահանջը բավարարում է։
True True True True False False (հնարավոր է փոքր թվերի համար իսկ հետո հնարավոր չէ մեծերի դեպքում)։ Այս դեպքում մենք ման փնտրում ենք վերջին True արժեքը՝ ամենամեծ արժեքը, որի դեպքում խնդրի պահանջը բավարարվում է։
Մեր խնդրում ցանկանում ենք, որ ծառերը տնկվեն հնարավորինս նոսր, այսինքն՝ նվազագույն հեռավորությունը լինի որքան հնարավոր է մեծ։ Եթե որոշակի մեծություն x-ով հնարավոր է տնկիները տեղակայել, ուրեմն ավելի փոքր արժեքների դեպքում նույնպես հնարավոր կլինի դա անել (ավելի խիտ տարբերակով)։
Տրամաբանական, բայց դանդաղ մոտեցում կլինի հերթականորեն ստուգել բոլոր հնարավոր հեռավորությունները՝ սկսած 1-ից, 2-ից, 3-ից և այսպես շարունակ՝ ստուգել, թե արդյոք կարելի է ծառերը տեղակայել նվազագույնը տվյալ հեռավորությամբ։
Մինչև անցնել երկակի որոնման տարբերակին, խորհուրդ է տրվում ձեզ ինքնուրույն փորձել գրել լուծումը և միայն դրանից հետո կարդալ մնացածը։
Երկուական որոնում (Binary Search) մեթոդով լուծելու դեպքում մենք բաժանում ենք գործընթացը 2 մասի – ստուգման գործառույթ և հենց երկակի որոնման մաս:
n, t = ...
x = sorted(x)
def check(d):
""" Ստուգում է, թե արդյոք կարելի է տնկել t ծառեր, որպեսզի դրանց միջև հեռավորությունը լինի նվազագույնը d """
planted = 0 # Պետք է տնկենք t ծառ (այժմ տնկված է 0)
prev = float('-inf') # Նախորդ տնկված ծառի կոորդինատը
for xi in x:
if xi - prev >= d: # Եթե xi կոորդինատում կարելի է տնկել նոր ծառ
planted += 1
prev = xi
return planted >= t
Այստեղ, ստուգման գործառույթը հաշվում է, թե քանի ծառ հնարավոր կլինի տնկել, եթե պահանջը լինի, որ ցանկացած երկու ծառերի միջև հեռավորությունը լինի ոչ պակաս, քան d-ն։
Այնուհետև կիրառում ենք երկուական որոնում պատասխանի վրա՝ որոնելու մեծագույն d-ն, որի դեպքում check(d)-ն կտա True:
l, r = 1, max(x)
while r - l > 1:
mid = (l + r) // 2
if check(mid):
l = mid
else:
r = mid
print(l)
Այսպես, վերջում ստանում ենք վերջապես l հեռավորությունը, որը կլինի հենց այն մեծագույն հեռավորությունը, որի դեպքում հնարավոր է ծառերը տնկել անհրաժեշտ ձևով։