DDD Runde 2, 2015 – Facitliste

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
Dansk Datalogi Dyst 2015
DDD Runde 2
4.–19. februar, 2015
linetest • DK • v1.0
Line Test
Sigurd er begyndt i gymnasiet og har lært om linjer p˚
a formen
f (x) = ax + b. Han har prøvet at tegne nogle linjer p˚
a papir for at
finde ud af hvilke koordinater der ligger under linjen, over linjen og
p˚
a linjen.
p1
Sigurd er dog blevet træt af at tegne, s˚
a 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
p2
Givet linjen ax + b og et heltal y skal du afgøre om ax + b < y,
ax + b > y eller ax + b = y.
Input
En enkelt linje best˚
aende af 4 heltal: a, x, b, y i den rækkefølge.
(0,0)
Output
En linje med teksten UNDER hvis ax + b > y, OVER hvis ax + b < y
og LINJE hvis ax + b = y.
Eksempler
Input
Output
Kommentarer
1 2 3 5
LINJE
1 · 2 + 3 = 5, s˚
a punktet (2, 5) ligger p˚
a
linjen.
Input
Output
1 2 3 4
UNDER
Input
Output
3 4 -10 50
OVER
Pointgivning
Delopgave 1 (70 point): −104 ≤ a, x, b ≤ 104 og −109 ≤ y ≤
109 .
Delopgave 2 (30 point): −108 ≤ a, x, b ≤ 108 og −1017 ≤ y ≤
1017 .
Side 1 af 2
Dansk Datalogi Dyst 2015
4.–19. februar, 2015
DDD Runde 2
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
4
5
6
7
8
9
y2 = a * x + b
if y2 < y :
print " OVER "
elif y2 > y :
print " UNDER "
else :
print " LINJE "
4
Dansk Datalogi Dyst 2015
4.–19. februar, 2015
DDD Runde 2
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˚
a 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˚
a vil han gerne have et mellemrum mellem de to cifre.
Hvis han f.eks. vil vise tallet 18 ser det s˚
aledes 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˚
aledes ud:
+|#
|
|#
|
|#
+-
-----+
#
#|
#
#|
#
#|
#
#|
#
#|
-----+
Alts˚
a 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˚
a displayet.
Side 1 af 3
Dansk Datalogi Dyst 2015
Opgave
DDD Runde 2
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˚
aende af 9 tegn som forestiller displayet som beskrevet herover.
Eksempler
Input
Output
Kommentarer
18 0
+-------+
| # ###|
| # # #|
| # ###|
| # # #|
| # ###|
+-------+
Se forklaring i opgavebeskrivelsen
Input
Output
Kommentarer
31 3
+|#
|
|#
|
|#
+-
Se forklaring i opgavebeskrivelsen
-----+
#
#|
#
#|
#
#|
#
#|
#
#|
-----+
Side 2 af 3
Dansk Datalogi Dyst 2015
DDD Runde 2
4.–19. februar, 2015
Input
Output
99 1
Kommentarer
urdisplay • DK • v1.1
Bemærk at der stadig skrives en blank
kolonne ud i starten. Alts˚
a 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
2
3
4
5
6
7
8
9
10
digits = [[ " ### " ,
[" #",
[ " ### " ,
[ " ### " ,
["# #",
[ " ### " ,
[ " ### " ,
[ " ### " ,
[ " ### " ,
[ " ### " ,
"#
"
"
"
"#
"#
"#
"
"#
"#
#",
#",
#",
#",
#",
",
",
#",
#",
#",
"# #",
" #",
" ### " ,
" ### " ,
" ### " ,
" ### " ,
" ### " ,
" #",
" ### " ,
" ### " ,
"#
"
"#
"
"
"
"#
"
"#
"
#",
#",
",
#",
#",
#",
#",
#",
#",
#",
" ### " ] ,
" #"],
" ### " ] ,
" ### " ] ,
" #"],
" ### " ] ,
" ### " ] ,
" #"],
" ### " ] ,
" ### " ]]
#0
#1
#2
#3
#4
#5
#6
#7
#8
#9
11
12
n , C = map ( int , raw_input () . split () )
13
14
15
a = ( n /10)
b = n %10
16
17
18
19
20
21
out = [ " " for x in range (7) ]
out [0] = " + - - - - - - -+ "
out [6] = " + - - - - - - -+ "
for i in range (1 ,6) :
out [ i ] = " | " + digits [ a ][ i -1] + " " + digits [ b ][ i -1] + " | "
22
23
24
25
if C != 0:
for i in range (0 ,7) :
out [ i ] = out [ i ][:( C -1) ]+ " " + out [ i ][ C :]
26
27
28
for i in range (0 ,7) :
print out [ i ]
8
Dansk Datalogi Dyst 2015
Lejrtur
DDD Runde 2
4.–19. februar, 2015
lejrtur • DK • v1.1
Sigurds klasse er taget p˚
a 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˚
a øer som Sigurd
netop kan st˚
a p˚
a sammen med sin planke. Sigurds plan er at bruge planken som bro til at n˚
a
en ø, og s˚
a flytte planken og bruge den som bro til at n˚
a en ny ø indtil han er n˚
aet over p˚
a
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˚
a 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˚
a 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˚
ar 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 ≤ 104 .
Side 1 af 2
Dansk Datalogi Dyst 2015
Output
DDD Runde 2
4.–19. februar, 2015
lejrtur • DK • v1.1
En enkelt linje med teksten SUCCES hvis det er muligt for Sigurd at n˚
a den anden side eller
teksten FORTABT hvis det ikke kan lade sig gøre.
Eksempler
Input
Output
Kommentarer
10 60 1
0 30
SUCCES
Sigurd kan lige netop n˚
a ud til øen og lige
netop n˚
a fra øen i land p˚
a den anden side
(begge afstande er 30m).
Input
Output
Kommentarer
10 61 1
0 30
FORTABT
Her er afstanden fra øen til den anden side
for lang (31m), s˚
a Sigurd kan ikke n˚
a over
floden.
Input
Output
Kommentarer
30 70 2
10 30
20 40
SUCCES
Sigurd g˚
ar først ud til ø nummer 1, som ligger 30m fra land. S˚
a g˚
ar han fra ø nummer
1 til nummer 2 og s˚
a i land p˚
a 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
2
def distSq (x , y ) :
return x * x + y * y
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
L ,W , n = map ( int , raw_input () . split () )
xs = [0 for i in range ( n ) ]
ys = [0 for i in range ( n ) ]
for i in range ( n ) :
xs [ i ] , ys [ i ] = map ( int , raw_input () . split () )
visited = [ False for i in range ( n ) ]
toVisit = []
for i in range ( n ) :
if ys [ i ] <= 30:
toVisit . append ( i )
visited [ i ] = True
while len ( toVisit ) > 0:
i = toVisit . pop ()
for j in range ( n ) :
if ( not visited [ j ]) and distSq ( xs [ i ] - xs [ j ] , ys [ i ] - ys [ j ]) <= 30*30:
toVisit . append ( j )
visited [ j ] = True
success = False
for i in range ( n ) :
if visited [ i ] and ys [ i ] >= W -30:
success = True
if success :
print " SUCCES "
else :
print " FORTABT "
11
Dansk Datalogi Dyst 2015
DDD Runde 2
4.–19. februar, 2015
temperatur • DK • v1.1
Temperatur
Sigurd har f˚
aet en hjemmeopgave, hvor de skal analysere temperaturen i løbet af ˚
aret. Sigurd
har besluttet, at han gerne vil undersøge mediantemperaturen i løbet af ˚
aret. 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˚
aler, 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˚
ale.
Til det har han opsøgt dig for at finde hjælp.
Opgave
Givet temperaturerne for alle de dage Sigurd har foretaget m˚
alinger skal du beregne medianen
for m˚
alingerne 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˚
ar af en m˚
aling i form af et heltal ai . Den i’te linje
svarer til m˚
alingen p˚
a den i’te dag.
−109 ≤ ai ≤ 109
Output
For hver af de n m˚
alinger ai skal du skrive en linje med medianen af de første i m˚
alinger
(a1 , . . . , ai ). Output skal være i samme rækkefølge som input.
Eksempler
Input
Output
Kommentarer
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
Dansk Datalogi Dyst 2015
4.–19. februar, 2015
Input
Output
6
1000
998
-1000
5
3
5
1000
999
998
501.5
5
5
DDD Runde 2
temperatur • DK • v1.1
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
4
5
def solve ( n ) :
lo = []
hi = []
6
7
8
9
10
11
12
13
14
15
16
# First handle cases n = 1 ,2 to make the loop easier cause I ’m a bad
# programmer .
a = int ( raw_input () )
print a
if n == 1:
return
b = int ( raw_input () )
print ( a + b ) *0.5
lo = [ min (a , b ) * -1]
hi = [ max (a , b ) ]
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
for i in range (2 , n ) :
a = int ( raw_input () )
if i %2 == 0: # Odd number . Add to lo
b = heapq . heappop ( hi )
heapq . heappush ( lo , min (a , b ) * -1)
heapq . heappush ( hi , max (a , b ) )
x = heapq . heappop ( lo )
print -x
heapq . heappush ( lo , x )
else :
b = - heapq . heappop ( lo )
heapq . heappush ( lo , min (a , b ) * -1)
heapq . heappush ( hi , max (a , b ) )
x1 , x2 = heapq . heappop ( lo ) , heapq . heappop ( hi )
print ( - x1 + x2 ) *0.5
heapq . heappush ( lo , x1 )
heapq . heappush ( hi , x2 )
35
36
37
38
solve ( int ( raw_input () ) )
14
Dansk Datalogi Dyst 2015
Trekant
4.–19. februar, 2015
DDD Runde 2
trekant • DK • v1.3
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 arealet1 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. x og y koordinatet af et af
punkterne. Det gælder, at −104 ≤ x, y ≤ 104 .
Output
En linje med arealet af den største trekant. Dit svar skal have en absolut præcision p˚
a 10−6
−6
(dvs. højest være 10 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
Dansk Datalogi Dyst 2015
DDD Runde 2
4.–19. februar, 2015
trekant • DK • v1.3
Input
Output
Kommentarer
4
1
1
6
6
12.5
Den største trekant
(1, 1), (6, 1), (6, 6)
Input
Output
Kommentarer
4
1
2
3
3
1
Bemærk, at det er okay hvis dit program
skriver 1.0, 1.0000 eller lignende.
1
5
1
6
1
2
3
4
Input
Output
4
1
1
1
4
13.5
1
1
10
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
er
punkterne
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
2
# Better O ( n ^2) algorithm . Should get full points . Note that the rotating
# calipers part can be done in O ( n ) time as well .
3
4
5
6
# Cross product
def cross (o , a , b ) :
return ( a [0] - o [0]) * ( b [1] - o [1]) - ( a [1] - o [1]) * ( b [0] - o [0])
7
8
9
10
11
12
# Convex Hull . Taken from wikibooks
def convex_hull ( points ) :
points = sorted ( set ( points ) )
if len ( points ) <= 1:
return points
13
14
15
16
17
18
19
# Build lower hull
lower = []
for p in points :
while len ( lower ) >= 2 and cross ( lower [ -2] , lower [ -1] , p ) <= 0:
lower . pop ()
lower . append ( p )
20
21
22
23
24
25
26
# Build upper hull
upper = []
for p in reversed ( points ) :
while len ( upper ) >= 2 and cross ( upper [ -2] , upper [ -1] , p ) <= 0:
upper . pop ()
upper . append ( p )
27
28
return lower [: -1] + upper [: -1]
29
30
31
32
# Area of triangle
def area ( p1 , p2 , p3 ) :
return 0.5 * abs ( cross ( p1 , p2 , p3 ) )
33
34
35
36
37
38
n = int ( raw_input () )
p = [0]* n
for i in range ( n ) :
x , y = map ( int , raw_input () . split () )
p [ i ] = (x , y )
39
40
h = convex_hull ( p )
17
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
n = len ( h )
best = 0
# Rotating calipers
for a in range ( n ) :
b = ( a +1) % n
c = ( a +2) % n
while True :
while ( area ( h [ a ] , h [ b ] , h [( c +1) % n ]) >= area ( h [ a ] , h [ b ] , h [ c ]) ) :
c = ( c +1) % n
if ( area ( h [ a ] , h [( b +1) % n ] , h [ c ]) >= area ( h [ a ] , h [ b ] , h [ c ]) ) :
b = ( b +1) % n
continue
else :
break
56
57
best = max ( best , area ( h [ a ] , h [ b ] , h [ c ]) )
58
59
print best
18