DDD Runde 2, 2015 Facitliste Søren Dahlgaard og Mathias Bæk Tejs Knudsen Opgaver og løsninger til 2. runde af DDD 2015. 1
4. 19. februar, 2015 linetest DK v1.0 Line Test Sigurd er begyndt i gymnasiet og har lært om linjer på formen f(x) = ax + b. Han har prøvet at tegne nogle linjer på papir for at finde ud af hvilke koordinater der ligger under linjen, over linjen og på linjen. Sigurd er dog blevet træt af at tegne, så han vil gerne have hjælp af dig til at lave et program der kan afgøre det. Heldigvis for dig er Sigurd kun interesseret i heltal. Opgave p 1 Givet linjen ax + b og et heltal y skal du afgøre om ax + b < y, ax + b > y eller ax + b = y. p 2 Input En enkelt linje bestående af 4 heltal: a, x, b, y i den rækkefølge. Output (0,0) En linje med teksten UNDER hvis ax + b > y, OVER hvis ax + b < y og LINJE hvis ax + b = y. Eksempler 1 2 3 5 LINJE 1 2 + 3 = 5, så punktet (2, 5) ligger på linjen. Input Output 1 2 3 4 UNDER Input Output 3 4-10 50 OVER Pointgivning Delopgave 1 (70 point): 10 4 a, x, b 10 4 og 10 9 y 10 9. Delopgave 2 (30 point): 10 8 a, x, b 10 8 og 10 17 y 10 17. Side 1 af 2
4. 19. februar, 2015 linetest DK v1.0 Begrænsninger Tidsbegrænsning: 1 s. Hukommelsesbegrænsning: 256 MB. Side 2 af 2
1 Løsning Linetest kan løses ved at læse de 4 tal og udføre beregningerne som beskrevet i opgaven. Dette er gjort i følgende Python kode: 1 a,x,b,y = map (int, raw_input (). split ()) 2 3 y2 = a* x+b 4 if y2 < y: 5 print " OVER " 6 elif y2 > y: 7 print " UNDER " 8 else : 9 print " LINJE " 4
4. 19. februar, 2015 urdisplay DK v1.1 Ur Display Sigurd har fundet et display, der er netop 7 9 felter, som han gerne vil programmere til at vise et to-cifret tal med en fin ramme. Hvert felt på displayet kan vise enten ingenting eller et af følgende tegn #, +, -,. Sigurd har fundet ud af at han kan vise et tal ved at bruge 5 3 felter som det ses herunder: ### # ### ### # # ### ### ### ### ### # # # # # # # # # # # # # # # # # ### ### ### ### ### # ### ### # # # # # # # # # # # # # ### # ### ### # ### ### # ### ### Til rammen vil han bruge +, -, og så vil han gerne have et mellemrum mellem de to cifre. Hvis han f.eks. vil vise tallet 18 ser det således ud: +-------+ # ### # # # # ### # # # # ### +-------+ Bemærk, at der er to blanke kolonner foran 1-tallet da alle tal fylder netop tre kolonner. Det kan dog ske at en af kolonnerne i displayet ikke virker, og I det tilfælde vil Sigurd ikke skrive noget til den kolonne. Hvis f.eks. d. 3. kolonne ikke virker, og Sigurd vil vise tallet 31, vil det se således ud: +- -----+ # # # # # # # # # # # # # +- -----+ Altså skrives hverken ramme eller midterste kolonne af 3-tallet ud. Sigurd har bedt dig om hjælp til at skrive et program der læser et to-cifret tal og udskriver det med 7 9 tegn som det ville se ud på displayet. Side 1 af 3
Opgave 4. 19. februar, 2015 urdisplay DK v1.1 Givet et tal samt hvilken kolonne der ikke virker skal du udskrive hvordan displayet skal se ud. Input En enkelt linje med 2 tal: Først det to-cifrede tal 10 n 99, der skal skrives ud. Dernæst et tal 0 C 8 der indikerer hvilken kolonne der ikke virker. C = 0 betyder at alle kolonner virker. Bemærk at den sidste kolonne (kolonne 9) altid virker! Output 7 linjer hver bestående af 9 tegn som forestiller displayet som beskrevet herover. Eksempler 18 0 +-------+ # ### # # # # ### # # # # ### +-------+ Se forklaring i opgavebeskrivelsen 31 3 +- -----+ # # # # # # # # # # # # # +- -----+ Se forklaring i opgavebeskrivelsen Side 2 af 3
4. 19. februar, 2015 urdisplay DK v1.1 99 1 -------+ ### ### # # # # ### ### # # ### ### -------+ Bemærk at der stadig skrives en blank kolonne ud i starten. Altså indeholder hver linje netop 9 tegn. Pointgivning Delopgave 1 (50 point): C = 0. Delopgave 2 (50 point): 0 C 8. Begrænsninger Tidsbegrænsning: 1 s. Hukommelsesbegrænsning: 256 MB. Side 3 af 3
2 Løsning I urdisplay skal vi bygge den tekst vi vil skrive ud. Dette kan f.eks. gøres ved at gemme de forskellige tal i en liste eller et array, og indeksere ind i denne. Husk at tage højde for den kolonne, der ikke skal udskrives! 1 digits = [["### ", "# #", "# #", "# #", " ### "], #0 2 [" #", " #", " #", " #", " #"], #1 3 [" ### ", " #", " ### ", "# ", " ### "], #2 4 [" ### ", " #", " ### ", " #", " ### "], #3 5 ["# #", "# #", " ### ", " #", " #"], #4 6 [" ### ", "# ", " ### ", " #", " ### "], #5 7 [" ### ", "# ", " ### ", "# #", " ### "], #6 8 [" ### ", " #", " #", " #", " #"], #7 9 [" ### ", "# #", " ### ", "# #", " ### "], #8 10 [" ### ", "# #", " ### ", " #", " ### "]] #9 11 12 n,c = map (int, raw_input (). split ()) 13 14 a = (n /10) 15 b = n %10 16 17 out = ["" for x in range (7) ] 18 out [0] = "+-------+" 19 out [6] = "+-------+" 20 for i in range (1,6) : 21 out [i] = " " + digits [a][i -1] + " " + digits [b][i -1] + " " 22 23 if C!= 0: 24 for i in range (0,7) : 25 out [i] = out [i ][:(C -1) ]+" "+ out [i][c:] 26 27 for i in range (0,7) : 28 print out [ i] 8
Lejrtur Dansk Datalogi Dyst 2015 DDD Runde 2 4. 19. februar, 2015 lejrtur DK v1.1 Sigurds klasse er taget på lejrtur, men under et natløb er Sigurd faret vild, og han er nødt til at krydse en stor flod for at komme hjem. Sigurd har heldigvis fundet en 30m lang planke, som han kan bruge som bro til at krydse floden. I floden er der et antal små øer som Sigurd netop kan stå på sammen med sin planke. Sigurds plan er at bruge planken som bro til at nå en ø, og så flytte planken og bruge den som bro til at nå en ny ø indtil han er nået over på den anden side. Inden han begynder vil han dog godt have at vide om det overhovedet kan lade sig gøre givet placeringerne af øerne. L W Figure 1: Et eksempel hvor Sigurd har brugt planken til at bevæge sig over floden i venstre side. Opgave Givet flodens bredde, længde og placeringen af øerne skal du afgøre om det er muligt for Sigurd at komme over på den anden siden ved hjælp af sin planke. Input Den første linje indeholder tre heltal L, W og n, som er hhv. længden og bredden af floden og antallet af øer som Sigurd kan bruge til at komme over på den anden side. De næste n linjer indeholder hver to heltal 0 x L og 0 y W som er positionen af en ø i floden. Floden går fra koordinat (0, 0) til (L, W ). Koordinat (0, 30) svarer til en ø 30m ude i vandet helt i venstre side af floden. Sigurds planke er altid 30m lang. Det vil altid gælde, at 1 L, W 10 4. Side 1 af 2
Output 4. 19. februar, 2015 lejrtur DK v1.1 En enkelt linje med teksten SUCCES hvis det er muligt for Sigurd at nå den anden side eller teksten FORTABT hvis det ikke kan lade sig gøre. Eksempler 10 60 1 0 30 SUCCES Sigurd kan lige netop nå ud til øen og lige netop nå fra øen i land på den anden side (begge afstande er 30m). 10 61 1 0 30 FORTABT Her er afstanden fra øen til den anden side for lang (31m), så Sigurd kan ikke nå over floden. 30 70 2 10 30 20 40 SUCCES Sigurd går først ud til ø nummer 1, som ligger 30m fra land. Så går han fra ø nummer 1 til nummer 2 og så i land på den anden side. Bemærk, at afstanden fra ø nummer 1 til ø nummer 2 er mindre end 30 (nemlig 10 2m), men det er ikke noget problem. Pointgivning Delopgave 1 (20 point): 1 n 5000. Alle øer har samme x-koordinat. Delopgave 2 (80 point): 1 n 5000. Begrænsninger Tidsbegrænsning: 1 s. Hukommelsesbegrænsning: 256 MB. Side 2 af 2
3 Løsning Lejrtur kan ses som en klassisk anvendelse af flood fill: Vi holder styr på om vi har været ved hver ø. Når vi besøger en ny ø finder vi alle øer inden for 30 meters afstand og besøger dem rekursivt. For 20 point er det nok, at sortere øerne efter y-koordinat og se om denne rækkefølge kan nå fra den ene til den anden side uden afstande over 30m. 1 def distsq (x, y): 2 return x* x+y* y 3 4 L,W,n = map (int, raw_input (). split ()) 5 xs = [0 for i in range ( n)] 6 ys = [0 for i in range ( n)] 7 for i in range ( n): 8 xs[i],ys[i] = map (int, raw_input (). split ()) 9 visited = [ False for i in range ( n)] 10 tovisit = [] 11 for i in range ( n): 12 if ys[ i] <= 30: 13 tovisit. append (i) 14 visited [ i] = True 15 while len ( tovisit ) > 0: 16 i = tovisit. pop () 17 for j in range ( n): 18 if ( not visited [j]) and distsq (xs[i]-xs[j], ys[i]-ys[j]) <= 30*30: 19 tovisit. append (j) 20 visited [ j] = True 21 success = False 22 for i in range ( n): 23 if visited [ i] and ys[ i] >= W -30: 24 success = True 25 if success : 26 print " SUCCES " 27 else : 28 print " FORTABT " 11
4. 19. februar, 2015 temperatur DK v1.1 Temperatur Sigurd har fået en hjemmeopgave, hvor de skal analysere temperaturen i løbet af året. Sigurd har besluttet, at han gerne vil undersøge mediantemperaturen i løbet af året. Medianen af n tal er den midterste værdi, hvis n er ulige, og gennemsnittet af de to midterste værdier, hvis n er lige. F.eks. er medianen af (1, 3, 5, 8, 8) lig med 5, og medianen af (1, 4, 4, 5, 6, 7) er 4.5. For at undersøge mediantemperaturen har Sigurd bygget en temperaturmåler, som giver ham en temperatur om dagen. Hver dag kunne Sigurd godt tænke sig at vide hvad mediantemperaturen har været siden han startede med at måle. Til det har han opsøgt dig for at finde hjælp. Opgave Givet temperaturerne for alle de dage Sigurd har foretaget målinger skal du beregne medianen for målingerne fra starten til hver enkelt dag. Input Første linje indeholder et heltal n, som er antallet af dage. Herefter følger n linjer, som hver består af en måling i form af et heltal a i. Den i te linje svarer til målingen på den i te dag. 10 9 a i 10 9 Output For hver af de n målinger a i skal du skrive en linje med medianen af de første i målinger (a 1,..., a i ). Output skal være i samme rækkefølge som input. Eksempler 5 4 3 1 8 6 4 3.5 3 3.5 4 Medianen af 4 er 4 Medianen af (4, 3) er (4 + 3)/2 = 3.5 Medianen af (1, 3, 4) er 3 osv. Side 1 af 2
Input 6 1000 998-1000 5 3 5 4. 19. februar, 2015 temperatur DK v1.1 Output 1000 999 998 501.5 5 5 Pointgivning Delopgave 1 (50 point): 1 n 1000 Delopgave 2 (50 point): 1 n 200000 Begrænsninger Tidsbegrænsning: 5 s. Hukommelsesbegrænsning: 256 MB. Side 2 af 2
4 Løsning For 50 point i temperatur er det tilstrækkeligt, at sortere alle tallene hver gang man læser et nyt. I listen af sorterede tal er det nemt at finde medianen hurtigt. For fuld point kan man enten bruge en træstruktur eller en prioritetskø (http://en.wikipedia. org/wiki/priority_queue). I prioritetskø-løsningen vil man have to køer: En til den største halvdel af tal og en til den laveste halvdel. For at finde medianen skal vi nu blot kigge på det største tal i den laveste halvdel og det mindste tal i den største halvdel. 1 import heapq 2 3 def solve (n): 4 lo = [] 5 hi = [] 6 7 # First handle cases n = 1,2 to make the loop easier cause I m a bad 8 # programmer. 9 a = int ( raw_input ()) 10 print a 11 if n == 1: 12 return 13 b = int ( raw_input ()) 14 print ( a+b) *0.5 15 lo = [ min (a,b) * -1] 16 hi = [ max (a,b)] 17 18 for i in range (2,n): 19 a = int ( raw_input ()) 20 if i%2 == 0: # Odd number. Add to lo 21 b = heapq. heappop (hi) 22 heapq. heappush (lo, min (a,b) * -1) 23 heapq. heappush (hi, max (a,b)) 24 x = heapq. heappop (lo) 25 print -x 26 heapq. heappush (lo,x) 27 else : 28 b = -heapq. heappop (lo) 29 heapq. heappush (lo, min (a,b) * -1) 30 heapq. heappush (hi, max (a,b)) 31 x1,x2 = heapq. heappop (lo), heapq. heappop (hi) 32 print (-x1+x2) *0.5 33 heapq. heappush (lo,x1) 34 heapq. heappush (hi,x2) 35 36 37 38 solve ( int ( raw_input ())) 14
4. 19. februar, 2015 trekant DK v1.3 Trekant Sigurds lærer har givet sigurd en mængde af n punkter i planen og bedt Sigurd om at finde arealet af den største trekant udspændt af tre af punkterne. Dette er illustreret i Figur 1. Dette kan Sigurd dog ikke finde ud af, og han vil gerne bede dig om hjælp. Figure 1: Eksempel af 7 punkter i planen og den størst udspændte trekant markeret. Opgave Givet n punkter i planen skal du beregne arealet 1 af den største trekant udspændt af tre af punkterne. Input Den første linje indeholder et heltal n, der er antallet af punkter. De næste n linjer indeholder hver to heltal x, y som er hhv. punkterne. Det gælder, at 10 4 x, y 10 4. Output x og y koordinatet af et af En linje med arealet af den største trekant. Dit svar skal have en absolut præcision på 10 6 (dvs. højest være 10 6 fra det rigtige svar). Bemærk at der godt kan være mere end en trekant med størst areal. Eksempler 1 Se f.eks. http://en.wikipedia.org/wiki/triangle#computing_the_area_of_a_triangle Side 1 af 2
4. 19. februar, 2015 trekant DK v1.3 4 1 1 1 5 6 1 6 6 12.5 Den største trekant er punkterne (1, 1), (6, 1), (6, 6) 4 1 1 2 2 3 3 3 4 1 Bemærk, at det er okay hvis dit program skriver 1.0, 1.0000 eller lignende. Input 4 1 1 1 1 1 10 4 5 Output 13.5 Pointgivning Delopgave 1 (75 point): 3 n 100. Delopgave 2 (25 point): 3 n 5000. Begrænsninger Tidsbegrænsning: 1 s. Hukommelsesbegrænsning: 256 MB. Side 2 af 2
5 Løsning For at få 75 point er det nok at loope over samtlige 3 punkter i sættet og finde de 3 punkter der udgør den største trekant. For at få fuld point skal man først finde det konvekse hylster af punkterne (http://en.wikipedia. org/wiki/convex_hull). Vi skal derefter finde den største trekant udspændt af tre punkter på det konvekse hylster. Bemærk, at der kan være mange punkter på det konvekse hylster, så vi kan ikke bare prøve alle trekanter. Der er mange måder at gøre det effektivt dog. En måde er at fastsætte to punkter og finde det tredje ved hjælp af en ternary search. Dette kan vi gøre, fordi arealet af trekanten givet det tredje punkt er en unimodal funktion, hvis vi kigger på punkterne der ligger mellem de to fastsatte punkter på det konvekse hylster. En anden, og måske nemmere måde, kan læses på følgende link: http://stackoverflow.com/ a/1621913. Denne løsning er implementeret i koden herunder. 1 # Better O( n ^2) algorithm. Should get full points. Note that the rotating 2 # calipers part can be done in O( n) time as well. 3 4 # Cross product 5 def cross (o, a, b): 6 return (a [0] - o [0]) * (b [1] - o [1]) - (a [1] - o [1]) * (b [0] - o [0]) 7 8 # Convex Hull. Taken from wikibooks 9 def convex_hull ( points ): 10 points = sorted ( set ( points )) 11 if len ( points ) <= 1: 12 return points 13 14 # Build lower hull 15 lower = [] 16 for p in points : 17 while len ( lower ) >= 2 and cross ( lower [ -2], lower [ -1], p) <= 0: 18 lower. pop () 19 lower. append (p) 20 21 # Build upper hull 22 upper = [] 23 for p in reversed ( points ): 24 while len ( upper ) >= 2 and cross ( upper [ -2], upper [ -1], p) <= 0: 25 upper. pop () 26 upper. append (p) 27 28 return lower [: -1] + upper [: -1] 29 30 # Area of triangle 31 def area (p1, p2, p3): 32 return 0.5 * abs ( cross (p1, p2, p3)) 33 34 n = int ( raw_input ()) 35 p = [0]* n 36 for i in range ( n): 37 x,y = map (int, raw_input (). split ()) 38 p[i] = (x,y) 39 40 h = convex_ hull ( p) 17
41 42 n = len (h) 43 best = 0 44 # Rotating calipers 45 for a in range ( n): 46 b = (a +1) %n 47 c = (a +2) %n 48 while True : 49 while ( area (h[a], h[b], h[(c+1) %n]) >= area (h[a],h[b],h[c])): 50 c = (c +1) %n 51 if ( area (h[a],h[(b+1) %n], h[c]) >= area (h[a],h[b],h[c])): 52 b = (b +1) %n 53 continue 54 else : 55 break 56 57 best = max (best, area (h[a],h[b],h[c])) 58 59 print best 18