Chemin parcouru — Les-mathematiques.net The most powerful custom community solution in the world

Chemin parcouru

Bonjour,

l'exercice suivant est tiré de la 25ème Olympiade Italienne de mathématiques (année 2009).

Une puce se trouve initialement au point $(0,0)$ du plan euclidien. Elle fait ensuite $n$ sauts. Chaque saut est dans l'une des quatre directions cardinales (nord, est, sud ou ouest). Le premier saut a pour longueur $2^0$, le deuxième saut a pour longueur $2^1,$ le troisième saut a pour longueur $2^2$, et ainsi de suite, le $n$-ème saut a pour longueur $2^{n-1}$.
Montrer que si nous connaissons le nombre de sauts et la position finale, nous pouvons déterminer de façon unique le chemin pris par la puce.

Bon, en prenant $e_1=(1,0)$ et $e_2=(0,1)$, et en considérant le vecteur $u=\displaystyle\sum_{k=0}^{n-1}2^kv_k=\sum_{k=0}^{n-1}2^kw_k$ avec $v_k,w_k\in\{\pm e_1,\pm e_2\}$, on montre par récurrence sur $n$ que $v_k=w_k,\,\,\, k=0,1,\cdots,n-1$. On a ainsi montré l'existence et l'unicité du chemin pris par la puce.

Cependant, j'ai une question (peut-être bête), trouver un algorithme qui donne ce chemin. Concrètement, si la puce se trouve par exemple après $229$ sauts au point $(1789,2018)$, quel chemin a-t-elle emprunté ?

Cordialement,
Yan2

Réponses

  • Si la puce se trouve par exemple après 229 sauts au point (1789,2018), le chemin emprunté est :
    onooennsooossssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
    ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
    sssssssssssssssssssssssssssssn
    

    Script lua :
    directions =
    {
      o = {dir="x",sens=1},
      e = {dir="x",sens=-1},
      n = {dir="y",sens=1},
      s = {dir="y",sens=-1},
    }
    
    function calculerPos(str)
      local pos = { x = 0, y = 0 }
      local l = 1 
      for c in str:gmatch"." do
        local increment = directions[c]
        pos[increment.dir] = pos[increment.dir] + increment.sens * l
        l = l * 2
      end
      return pos
    end
    
    t = {"o","s","e","n"}
    helperUn = {[-1]={},[0]={},[1]={}}
    for k,v in pairs(t) do
      local xy=calculerPos(v)
      helperUn[xy.x][xy.y]=v
    end
    
    helperDeux = 
    {
      [0]={},
      [1]={},
      [2]={},
      [3]={},
    }
    for k,v in pairs(t) do
      for kk,vv in pairs(t) do
        local xy=calculerPos(v..vv)
        local x,y = (xy.x)%4,(xy.y)%4
        helperDeux[x][y]=v
      end
    end
    
    function calculerTraj(x,y,n)
      if n==1 then
        return helperUn[x][y]
      else
        local reponse = helperDeux[x%4][y%4]
        local tmp = calculerPos(reponse)
        local nx,ny = (x - tmp.x)/2,(y - tmp.y)/2
        return reponse..calculerTraj(nx,ny,n-1)
      end
    end
    

    Testé avec :
    sstr = calculerTraj(1789,2018,229)
    print(sstr)
    pos = calculerPos(sstr)
    print(pos.x,pos.y,#sstr)
    -- retourne 1789	2018	229
    

    Vérifié à la main (j'avais du mal à y croire, avec les 2^229 à calculer !)
    strVerif="onooennsooo"
    verif = calculerPos(strVerif)
    print(verif.x,verif.y,2018-verif.y,2^#strVerif)
    -- retourne 1789	-30	2048	2048.0
    
  • Bonjour Marsup,

    L'algorithme suivant, propose , pour passer du point $(0;0)$ au point $(1789; 2018)$ en 229 étapes, un cheminement qui débute par la séquence $ONOOENNSOOO$ suivie d 'une longue course effrénée vers le Sud et ponctuée par un grand bond en arrière vers le Nord. Ce n'est pas exactement la route que tu as suivie , mais c'est normal, car tu as trouvé original de coder $(1;0)$ par $O$ , alors que j'ai cru bon de faire $(1;0) =E$.
    Mes faibles compétences en algorithmique font que j'ai du mal à décrypter ton code, et je ne sais pas si "mon" algorithme est vraiment différent du tien.


    Entrer $x$,$y$ ,$n$ ($x,y,n \in\N^*, x,y$ de parités différentes, $(x,y)$ sont les coordonnées de l'objectif, $n$ le nombre d'étapes.)
    $i$ prend la valeur $0$.
    Tant que $x^2+y^2\neq1$ OU $i<n-1$
    $\:\:\:\: $ $a$ prend la valeur ($x\mod2)\times((x+y)\mod4-2)$ ($x\mod k$ désigne le reste de la division euclidienne de $x$ par $k$.)
    $\:\:\:\: $ $b$ prend la valeur ($y\mod2) \times((x+y)\mod4-2)$.
    $\:\:\:\: $ Afficher $(a, b)$. (en le codant par $O,E,N$ ou $S$.)
    $\:\:\:\:$ $ x$ prend la valeur $\frac{x-a}2$.
    $\:\:\:\: $ $y$ prend la valeur $\frac{y-b}2$.
    $\:\:\:\: $ $ i $ prend la valeur $i+1$.
    Fin du Tant que.
    Afficher $(x,y)$ ( en le codant par la direction cardinale adéquate).

    Si l'on souhaite obtenir l'unique chemin de longueur minimale allant de $(0;0)$ à $(x;y)$, il suffit de supprimer dans le "Tant que" la condition "OU $i<n-1$" ainsi que les lignes "$i$ prend la valeur $0$" et "$i$ prend la valeur $i+1$" qui ne servent plus à rien.
    Amicalement.
  • Ah désolé pour la confusion Ouest / Est je suis mal latéralisé.

    Mon algorithme consiste à coder l'application qui à une suite de mouvements associe la position finale (à l'erreur, que tu as relevée, près !)

    Pour revenir en arrière : des positions finales au trajet, je construis deux tableaux associatifs, qui permettent de ne faire aucun calcul à la main.

    helperUn ne sert que pour un trajet de longueur 1 : aux quatre positions possibles, après un saut, il associe la lettre correspondante.

    Donc helperDeux associe, lui aux seize couples $(x,y) \mod 4$ possibles après deux saut, le premier de ces deux sauts.

    La remarque fondamentale est que le premier saut d'une suite de longueur $n\ge 2$ quelconque est déterminé par la classe modulo 4 de $(x,y)$.

    La façon dont ce premier saut est déterminé ne dépend pas de $n$ à partir de $n\ge2$.

    helperDeux permet donc d'identifier le premier saut dans une suite de longueur $>1$ quelconque.

    Voilà tout, après, on résout récursivement.
  • La version chemin le plus court avec le test en $x^2 + y^2 = 1$ proposé par lou16.

    Aussi corrigé l'interversion est $\longleftrightarrow$ ouest.
    directions =
    {
      e = {dir="x",sens=1},
      o = {dir="x",sens=-1},
      n = {dir="y",sens=1},
      s = {dir="y",sens=-1},
    }
    
    function calculerPos(str)
      local pos = { x = 0, y = 0 }
      local l = 1 
      for c in str:gmatch"." do
        local increment = directions[c]
        pos[increment.dir] = pos[increment.dir] + increment.sens * l
        l = l * 2
      end
      return pos
    end
    
    helperUn = {[-1]={},[0]={},[1]={}}
    for k,v in pairs(directions) do
      local xy=calculerPos(k)
      helperUn[xy.x][xy.y]=k
    end
    
    helperDeux = {[0]={},[1]={},[2]={},[3]={}}
    for k,v in pairs(directions) do
      for kk,vv in pairs(directions) do
        local xy=calculerPos(k..kk)
        local x,y = (xy.x)%4,(xy.y)%4
        helperDeux[x][y]=k
      end
    end
    
    function calculerTraj(x,y,chemin)
      local chemin = chemin or ""
      if x^2 + y^2 == 1 then
        return chemin .. helperUn[x][y]
      else
        local reponse = helperDeux[x%4][y%4]
        local tmp = calculerPos(reponse)
        local nx,ny = (x - tmp.x)/2,(y - tmp.y)/2
        return calculerTraj(nx,ny,chemin..reponse) -- version tail recursive
      end
    end
    
    Vérif:
    sstr = calculerTraj(1789,2018)
    print(sstr) -- eneeonnseeen
    pos = calculerPos(sstr)
    print(pos.x,pos.y,#sstr) -- 1789	2018	12
    
Connectez-vous ou Inscrivez-vous pour répondre.
Success message!