Construisez des voies ferrées et trompez le gouvernement

30

Vous êtes un entrepreneur ferroviaire aux États-Unis au XIXe siècle, lorsque les trains deviennent populaires parce qu'ils sont le moyen le plus efficace de transporter de gros volumes de matériaux par voie terrestre. Il y a un besoin national de voies ferrées de la côte est à travers certaines terres récemment colonisées à l'ouest.

Pour répondre à ce besoin, le gouvernement américain va prélever une taxe pour subventionner les chemins de fer. Ils ont promis de payer de l'argent à votre compagnie de chemin de fer pour chaque kilomètre de voie posé. Étant donné que la pose de pistes dans les régions vallonnées et montagneuses est plus coûteuse que la pose de pistes dans les terres plates, elles ajustent la quantité qu'elles donnent en conséquence. Autrement dit, le gouvernement paiera

  • 5 000 $ par mille de voie posée sur un terrain plat
  • 12 500 $ par mille de voie posée sur un terrain vallonné
  • 20 000 $ par mille de voie posée dans les montagnes.

Bien sûr, ce plan ne reflète pas avec précision le coût réel de la pose des voies.

Vous avez engagé des cartographes pour dessiner des cartes en relief des régions où vous allez tracer une piste pour analyser l'altitude. Voici une telle carte:

S12321
121234
348E96

Chaque chiffre représente un mile carré de terrain. Sest le point de départ, Eest le point d'arrivée. Chaque nombre représente l'intensité des changements d'altitude dans cette région.

  • Le terrain numéroté 1-3 constitue un terrain plat.
  • Le terrain numéroté 4-6 constitue un terrain vallonné.
  • Le terrain numéroté 7-9 constitue une chaîne de montagnes.

Vous avez, grâce à des années d'expérience dans la construction de voies ferrées, évalué que le coût de la construction de voies (en dollars) satisfait cette formule:

Cost_Per_Mile = 5000 + (1500 * (Elevation_Rating - 1))

Cela signifie que la construction de certains gradients d'élévation vous coûtera plus d'argent que le gouvernement ne le donne, parfois ce sera rentable, et parfois vous atteindrez le seuil de rentabilité.

Par exemple, un mile de voie sur une pente d'élévation de 3 coûte 8000 $ à construire, mais vous ne payez que 5000 $ pour cela, vous perdez donc 3000 $. En revanche, construire un mile de voie sur une pente d'élévation de 7 coûte 14 000 $, mais vous êtes payé 20 000 $ pour cela: un bénéfice de 6 000 $!

Voici un exemple de carte, ainsi que deux chemins possibles différents.

S29    S#9    S##
134    1#4    1##
28E    2#E    2#E

La première piste coûte 30 000 $ à construire, mais le gouvernement vous paie 30 000 $. Vous ne tirez aucun profit de cette piste.

D'un autre côté, le second coûte 56 500 $ à construire, mais vous êtes payé 62 500 $ pour cela. Vous bénéficiez de 6 000 $ de cette piste.

Votre objectif: à partir d' une carte en relief, trouvez le chemin le plus rentable (ou peut-être simplement le moins cher) du début à la fin. Si plusieurs chemins sont liés, l'un d'eux est une solution acceptable.

Détails du programme

Vous obtenez une entrée de texte séparée par une carte rectangulaire de nombres et un point de début et de fin. Chaque nombre sera un entier compris entre 1 et 9. En dehors de cela, l'entrée peut être fournie comme vous le souhaitez, dans des limites raisonnables.

La sortie doit être au même format que l'entrée, avec les numéros où la piste a été construite remplacée par un hachage ( #). En raison des réglementations arbitraires imposées par certains politiciens capricieux, les pistes ne peuvent emprunter que des voies horizontales ou verticales. En d'autres termes, vous ne pouvez pas revenir en arrière ou aller en diagonale.

Le programme devrait être capable de résoudre dans un laps de temps raisonnable (c'est-à-dire <10 minutes) pour les cartes jusqu'à 6 lignes et 6 colonnes.

Il s'agit d'un défi de golf de code , donc le programme le plus court gagne.

J'ai un exemple d'implémentation (non-golfé) .

Exemple d'E / S

S12321
121234
348E96

S12321
######
3##E##



S73891
121234
348453
231654
97856E

S#3###
1###3#
3#####
######
#####E
Peter Olson
la source
Qu'est-ce que c'est, si la sortie est ambiguë?
FUZxxl
2
La sortie peut être ambiguë, mais ambiguë d'une manière où le profit est le même quelle que soit la façon dont vous le tracez.
Peter Olson
Je pense qu'il y a une petite erreur. Doit être 4dans 134l'exemple de carte 6?
JiminP
@JiminP Oui, c'était une erreur de changer les numéros à un endroit mais pas à un autre. Il devrait être corrigé maintenant.
Peter Olson
3
Trois ans plus tard, le gouvernement regarde autour de lui et commence à se demander pourquoi toutes les collines et montagnes sont couvertes de voies ferrées. Mais bon, les utilisateurs des transports en commun locaux ont eu un bon tour de montagnes russes / tour --- gratuitement --- financé par le gouvernement, ce qui rend les gens plus heureux, alors pourquoi s'en soucier? (* sauf pour certaines collines de grade 6)
John Dvorak

Réponses:

5

Python, 307 caractères

import os
I=os.read(0,99)
n=I.find('\n')+1
I='\0'*n+I+'\0'*n
def P(p):
 S=[]
 for d in(-n,-1,1,n):
  y=p[-1]+d
  if'E'==I[y]:S+=[(sum((int(I[v])-1)/3*75-15*int(I[v])+15for v in p[1:]),p)]
  if'0'<I[y]<':'and y not in p:S+=P(p+[y])
 return S
for i in max(P([I.find('S')]))[1][1:]:I=I[:i]+'#'+I[i+1:]
print I,

Pprend un chemin partiel pet renvoie toutes les façons de l'étendre pour atteindre E. Chaque chemin renvoyé est associé à son score afin que vous maxpuissiez trouver le meilleur.

Prend environ 80 secondes sur une carte 6x6.

Keith Randall
la source
1
Vous pouvez remplacer le deuxième niveau de retraits par des tabulations pour enregistrer 3 caractères
gnibbler
4

Python: 529 482 460 octets

Ma solution ne gagnera aucun prix. Cependant, comme il n'y a que deux solutions publiées et que j'ai trouvé le problème intéressant, j'ai quand même décidé de poster ma réponse.

Edit: Merci à Howard pour ses recommandations. J'ai réussi à raser une grande partie de mon score!

import sys
N=len
def S(m,c,p=0):
 if m[c]=='E':return m,p
 if m[c]<'S':
    b=list(m);b[c]='#';m=''.join(b)
 b=[],-float('inf')
 for z in(1,-1,w,-w):
    n=c+z
    if 0<=n<N(m)and m[n]not in('S','#')and(-2<z<2)^(n/w!=c/w):
     r=S(m,n,p+(0if m[n]=='E'else(int(m[n])-1)/3*5-int(m[n])+1))
     if b[1]<r[1]:b=r
 return b
m=''
while 1:
 l=sys.stdin.readline().strip()
 if l=='':break
 w=N(l);m+=l
b,_=S(m,m.index('S'))
for i in range(0,N(b),w):print b[i:i+w]
sadakatsu
la source
C'est comme ça que ça commence. :)
Jonathan Van Matre
1
Quelques améliorations mineures: Pet Mne sont utilisées qu'une seule fois donc c'est une bonne idée de s'aligner ensuite (pour une seule invocation cela fonctionne dans presque tous les cas pour deux parfois). m[c]!='S'peut être raccourci à m[c]<'S', également abs(z)==1à abs(z)<2ou même -2<z<2.
Howard
Vos "améliorations mineures" me font économiser 47 octets. J'édite ma réponse.
sadakatsu
3

Ruby, 233 caractères

R=->s{o=s=~/S/m
s=~/E/m?(q=[-1,1,-N,N].map{|t|s[f=o+t]>'0'?(n=s*1
n[o]='#'
n[f]='S'
a=R[n]
a&&[a[0]-(e=s[f].to_i-1)/3*5+e,a[1]]):nil}-[nil]
q.sort!&&q[0]):[0,(n=s*1;n[o]='E'
n[$_=~/S/m]='S'
n)]}
N=1+(gets(nil)=~/$/)
$><<R[$_+$/*N][1]

Une approche Ruby en force brute qui fonctionne bien dans les contraintes de temps sur une carte 6x6. L'entrée doit être donnée sur STDIN.

Exemples:

S12321
121234
348E96

S#2321
1#####
3##E##    
--    
S73891
121234
348453
231654
97856E

S#####
1212##
#####3
#3####
#####E
Howard
la source
@PeterOlson J'ai essayé d'accorder au moins un peu d'attention à votre défi ;-)
Howard