40 votes

Nombre minimum d'arrêts de gare

J'ai reçu cette question de l'entrevue et a été collée sur elle:

Il y a un nombre infini de train s'arrête à partir de la station de numéro 0.

Il y a un nombre infini de trains. Le n-ième train s'arrête à toutes les k * 2^(n - 1) s'arrête là où k est compris entre 0 et l'infini.

Lorsque n = 1, le premier train s'arrête à l'arrêt 0, 1, 2, 3, 4, 5, 6, etc.

Lorsque n = 2, le deuxième train s'arrête à l'arrêt 0, 2, 4, 6, 8, etc.

Lorsque n = 3, le troisième train s'arrête à l'arrêt 0, 4, 8, 12, etc.

Compte tenu de commencer numéro de la station et à la fin de la station de numéro de retour, le nombre minimum d'arrêts entre eux. Vous pouvez utiliser l'un des trains pour se rendre d'un arrêt à un autre arrêt.

Par exemple, le nombre minimum d'arrêts entre start = 1 et fin = 4 est 3, car nous pouvons obtenir à partir de 1 à 2 à 4.

Je suis en train de réfléchir à une programmation dynamique solution serait de stocker en dp[start][end] le nombre minimum d'étapes entre start et end. Nous aimerions construire le tableau à l'aide d' start...mid1, mid1...mid2, mid2...mid3, ..., midn...end. Mais je n'ai pas réussi à le faire fonctionner. Comment voulez-vous résoudre ce problème?

Précisions:

  1. Les Trains ne peuvent avancer qu'à partir d'un nombre inférieur de l'arrêter à un nombre plus élevé d'arrêt.
  2. Un train peut commencer à n'importe quelle station où il fait un arrêt au.
  3. Les Trains peuvent être embarqués dans n'importe quel ordre. N = 1 train peuvent être montés à bord avant ou après l'embarquement n = 3 train.
  4. Les Trains peuvent être embarqués à plusieurs reprises. Par exemple, il est autorisé à bord de la n = 1 train, à côté du conseil de la n = 2) former, et enfin du conseil de la n = 1 le train de nouveau.

28voto

SaiBot Points 2308

Je ne pense pas que vous avez besoin de la programmation dynamique à tous pour ce problème. Il peut être exprimé en binaire calculs.

Si vous convertissez le numéro d'une station de binaire, il vous dit tout de suite comment s'y rendre depuis la gare de 0, par exemple,

station 6 = 110

qui vous dit que vous avez besoin de prendre n=3 former et n=2) former chacun pour une seule station. Ainsi, le popcount de la représentation binaire vous indique le nombre d'étapes que vous avez besoin.

La prochaine étape est de comprendre comment obtenir à partir d'une station à l'autre. Mauvais afficher ce message par exemple. Dites que vous voulez obtenir à partir de la station de 7 à la station de 23.

station 7 = 00111

station 23 = 10111

La première chose que vous voulez faire est d'obtenir un arrêt intermédiaire. Cet arrêt est indiquée par

(le plus élevé de bits sont égaux en début et fin de la station) + (d'abord les différents bits) + (rempli avec des zéros)

Dans notre exemple, l'arrêt intermédiaire est de 16 (10000). Les étapes que vous devez effectuer peut être calculée par la différence du nombre et de la station de départ (7 = 00111). Dans notre exemple, cela donne

10000 - 00111 = 1001

Maintenant que vous connaissez, que vous avez besoin de 2 arrêts (n=1 train et n=4) pour obtenir de 7 à 16. La tâche restante est de passer de 16 à 23, là encore, cela peut être résolu par la différence correspondante

10111 - 10000 = 00111

Donc, vous avez besoin d'un autre 3 arrêts pour aller de 16 à 23 ans (n= 3, n= 2, n= 1). Cela vous donne 5 arrêts au total, seulement à l'aide de deux binaires différences et les popcount. La trajectoire résultante peut être extraite à partir des représentations en bits 7 -> 8 -> 16 -> 20 -> 22 -> 23

Edit:

Pour de plus amples précisions de l'arrêt intermédiaire supposons que nous voulons aller de

station 5 = 101 à

station 7 = 111

l'arrêt intermédiaire dans ce cas sera de 110, parce que

plus de bits sont égaux en début et fin de la station = 1

d'abord les différents bits = 1

rempli avec des zéros = 0

nous avons besoin d'une étape à y aller (110 - 101 = 001) et une de plus pour aller de là à la fin de la station (111 - 110 = 001).

À propos de l'arrêt intermédiaire

Le concept de l'arrêt intermédiaire est un peu maladroit, mais je ne pouvais pas trouver un moyen plus élégant dans l'ordre pour obtenir les opérations sur les bits de travail. L'escale est l'arrêt entre le début et la fin où le niveau le plus élevé de bits commutateurs (c'est pourquoi elle est construite de la façon dont il est). À cet égard, il est à l'arrêt au cours de laquelle le train le plus rapide (entre le début et la fin) fonctionne (en fait tous les trains que vous êtes capable d'attraper arrêter là).

En soustrayant l'arrêt intermédiaire (représentation binaire) à partir de la fin de la station (représentation binaire) vous réduire le problème pour le cas simple à partir de la station de 0 (cf. premier exemple de ma réponse).

En soustrayant la station de départ de l'escale vous également de réduire le problème au cas les plus simples, mais supposons que vous aller de l'arrêt intermédiaire à la station de départ, qui est l'équivalent dans l'autre sens.

23voto

user2357112 Points 37737

Tout d'abord, demandez si vous pouvez revenir en arrière. Il semble que vous ne pouvez pas, mais comme présentés ici (ce qui peut ne pas refléter la question que vous l'avez reçu), le problème ne donne jamais un sens explicite pour l'un de ces trains. (Je vois que vous avez modifié votre question de dire que vous ne pouvez pas revenir en arrière.)

En supposant que vous ne pouvez pas revenir en arrière, la stratégie est simple: toujours prendre le plus grand numéro de trains disponibles qui n'a pas de dépassement de votre destination.

Supposons que vous êtes à l'arrêt, s, et le plus grand numéro de train qui s'arrête à votre emplacement actuel et n'a pas de dépassement est de former k. Voyage une fois sur le train k va vous prendre pour arrêter l' s + 2^(k-1). Il n'y a pas de moyen plus rapide pour obtenir à cet arrêt, et pas moyen de faire sauter la stop - pas de numéros inférieurs trains passer aucun train ks'arrête, et pas de numéro supérieur arrêts des trains entre le train ks'arrête, donc vous ne pouvez pas obtenir sur un chiffre supérieur de train avant de vous y rendre. Ainsi, de former k est votre meilleur immédiate déplacer.

Avec cette stratégie, dans l'esprit, la plupart du reste de l'optimisation est une question d'efficacité peu tourner les astuces pour calculer le nombre d'arrêts, sans explicitement à comprendre chaque étape de l'itinéraire.

6voto

Yakk Points 31636

Je vais tenter de prouver mon algorithme est optimal.

L'algorithme est "prendre le train le plus rapide qui n'a pas de dépassement de votre destination".

Combien d'arrêts c'est un peu délicat.

Coder les deux arrêts comme des nombres binaires. Je demande que l'identique d'un préfixe peut être négligée; le problème de passer d' a de b est le même que le problème de passer d' a+2^n de b+2^n si 2^n > b, comme les arrêts entre 2^n et 2^(n+1) sont juste les arrêts entre 0 et 2^n changé au cours.

À partir de cela, nous pouvons réduire un voyage d' a de b garantir que le bit élevé de b est réglé, et le même "haute" peu d' a est pas définie.

Pour résoudre allant de 5 (101) à 7 (111), nous n'avons qu'à résoudre allant de 1 (01) 3 (11), puis shift notre arrêt des nombres jusqu'à 4 (100).

Pour aller d' x de 2^n + yy < 2^n (et donc de l' x est), nous voulons d'abord aller à l' 2^n, car il n'y a pas de trains qui saute 2^n qui ne sont pas aussi ignorer 2^n+y < 2^{n+1}.

Donc, n'importe quel ensemble d'arrêts entre x et y faut arrêter d' 2^n.

Ainsi, le nombre optimal de stations de l' x de 2^n + y le nombre de stations de l' x de 2^n, suivi par le nombre de stations de l' 2^n de 2^n+y, inclusivement (ou d' 0 de y, qui est la même).

L'algorithme que je propose pour l'obtenir à partir d' 0 de y est de commencer avec le bit de haute ensemble, et de prendre le train qui vous arrive là, alors allez sur le bas de la liste.

Réclamation: pour générer un numéro d' k 1s, vous devez prendre au moins k des trains. Comme preuve, si vous prenez un train et il ne cause pas de portage de votre numéro de l'arrêt, il définit 1 bit. Si vous prenez un train et il est la cause d'un report, le nombre a au plus 1 plus de bit de départ.

Pour obtenir de x de 2^n est un peu plus compliqué, mais peut être simple par le suivi des trains, vous prenez en arrière.

Cartographie s_i de s_{2^n-i} , et en inversant les marches du train, toute solution pour passer d' x de 2^n décrit une solution pour passer d' 0 de 2^n-x. Et toute solution optimale pour l'avant on est optimale pour l'arrière, et vice-versa.

À l'aide de la suite pour obtenir d' 0 de y, on obtient alors que l'itinéraire optimal à partir d' a de bb plus élevé ensemble de bits est - 2^n et a n'ont que peu ensemble est #b-2^n + #2^n-a# "signifie" le nombre de bits de la représentation binaire". Et en général, si a et b ont un préfixe commun, il suffit de déposer le préfixe commun.

Une règle locale qui génère le nombre d'étapes est de "prendre le train le plus rapide de votre position actuelle qui n'a pas de dépassement de votre destination".

Pour la partie allant de la 2^n de 2^n+y nous l'avons fait de manière explicite dans notre preuve ci-dessus. Pour la partie allant de la x de 2^n c'est plus difficile à voir.

Tout d'abord, si le bit de poids faible de x est défini, il faut évidemment prendre le premier et le seul train que nous pouvons prendre.

Deuxièmement, imaginez x a une certaine collection de unset bits, dire m d'entre eux. Si nous avons joué le jeu de train allant de x/2^m de 2^(n-m), puis mis à l'échelle du stop en multipliant par 2^m , nous aurions une solution pour aller de x de 2^n.

Et #(2^n-x)/2^m = #2^n - x. Donc, cette "échelle" solution est optimale.

À partir de cela, nous sommes toujours à prendre le train correspondant à notre faible-de l'ordre de bit dans cette solution optimale. C'est la plus longue plage de train disponibles, et il n'a pas de dépassement en 2^n.

CQFD

3voto

D Krueger Points 847

Ce problème ne nécessite pas de programmation dynamique.

Ici est une simple mise en œuvre d'une solution à l'aide de GCC:

uint32_t min_stops(uint32_t start, uint32_t end)
{
    uint32_t stops = 0;
    if(start != 0) {
        while(start <= end - (1U << __builtin_ctz(start))) {
            start += 1U << __builtin_ctz(start);
            ++stops;
        }
    }
    stops += __builtin_popcount(end ^ start);
    return stops;
}

Le train de schéma est une carte de puissances de deux. Si vous visualisez les lignes de train comme une représentation binaire, vous pouvez voir que le bit le plus bas représente la ligne de train la plus longue distance entre les arrêts que vous pouvez prendre. Vous pouvez également prendre les lignes avec des distances plus courtes.

Afin de minimiser la distance, vous voulez prendre la ligne la plus longue distance possible, jusqu'à ce que ferait la fin de la station inaccessible. C'est ce que l'ajout par les plus faibles taux de bit dans le code. Une fois que vous faites cela, un certain nombre de bits de poids sera d'accord avec les bits de poids à la fin de la station, tandis que les bits de poids faible sera égal à zéro.

À ce point, c'est tout simplement une question de prendre un train pour le bit le plus élevé à la fin de la station qui n'est pas défini dans la station actuelle. C'est optimisée en tant que __builtin_popcount dans le code.

Un exemple allant de 5 à 39:

000101 5        // Start
000110 5+1=6
001000 6+2=8
010000 8+8=16
100000 16+16=32 // 32+32 > 39, so start reversing the process
100100 32+4=36  // Optimized with __builtin_popcount in code
100110 36+2=38  // Optimized with __builtin_popcount in code
100111 38+1=39  // Optimized with __builtin_popcount in code

2voto

גלעד ברקן Points 3044

Comme certains l'ont souligné, depuis les arrêts sont tous des multiples de puissances de 2, les trains qui s'arrêtent de plus en plus fréquemment également un arrêt à la même arrêts de la plus-trains express. Tout arrêt se trouve sur le premier train de la route, qui s'arrête à chaque station. Tout arrêt est au plus 1 unité à partir de la deuxième train de la route, s'arrêtant à chaque seconde de la station. Tout arrêt est à plus de 3 unités à partir de la troisième train qui s'arrête à chaque quatrième station, et ainsi de suite.

Donc, commencer à la fin et de tracer votre itinéraire de retour dans le temps - hop le plus proche multiple d'une puissance de 2 de former et de retenir de commutation pour le plus grand multiple d'une puissance de 2 train, vous pouvez dès que possible (vérifier la position de la moins importante de bit - pourquoi? multiples de puissances de 2 peut être divisé par deux, c'est un peu décalée vers la droite, sans laisser de reste, journal 2 fois, ou comme beaucoup de zéros dans les bits de la représentation), aussi longtemps que son intervalle de ne pas rater le point de départ après un arrêt. Lorsque celui-ci est le cas, effectuez le commutateur d'inversion, en sautant sur le côté inférieur multiple d'une puissance de 2) former et y rester jusqu'à ce que son intervalle de ne pas rater le point de départ après un arrêt, et ainsi de suite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X