Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: amchacon en 12 Junio 2013, 23:22 pm



Título: Obtener ruta más corta
Publicado por: amchacon en 12 Junio 2013, 23:22 pm
Me encuentro en un problema un poco elemental. A ver si alguien me puede dar alguna pista de como resolverlo.

Tenemos una cuadrícula tal que:

(http://www.paintfacil.es/resources/cuadricula12x10p.bmp)

Ahí tenemos dos cuadrados pintados:

(http://imageshack.us/a/img94/4017/sintitulod.png)

Partiendo del cuadrado rojo, tenemos que obtener una ruta para llegar al cuadrado azul (moviendose verticalmente/horizontalmente). Para complicar más la cosa ponemos algunos obstaculos aleatorios:

(http://imageshack.us/a/img835/2999/sintitulo2r.png)

La ruta más corta sería:

(7,2)
(7,9)
(10,9)


¿Cómo podríamos implementar esto en C++?


Título: Re: Obtener ruta más corta
Publicado por: aguml en 13 Junio 2013, 00:03 am
yo no te puedo ayudar en eso pero alguna vez he preguntado por algo parecido y me comentaron que buscara info sobre como se crean juegos y sobre los algoritmos de colisiones asi que supongo que es lo que necesitas.


Título: Re: Obtener ruta más corta
Publicado por: xiruko en 14 Junio 2013, 23:26 pm
Citar
La ruta más corta sería:
(7,2)
(7,9)
(10,9)

De hecho hay varias que son las más cortas. La que indicas es de 14 cuadrados, igual que por ejemplo, (2, 7) - (9, 7) - (9, 10) o (8, 2) - (8, 3) - (9, 3) - (9, 10), donde el primer número sería la fila y el segundo la columna.

Como primera aproximación, podrías intentar que el cuadrado rojo vaya alternativamente hacia la coordenada x e y del cuadrado azul. Es decir, primero intente ir hasta la coordenada x, si llega a la fila o columna donde está el azul o choca con algo que entonces intente ir hasta la y, si vuelve a chocar que vaya a la x, etc. y así hasta que llegue. En el ejemplo que pones, este algoritmo daría alguna de las soluciones que te he comentado arriba.

Igualmente es demasiado simple así que no le pidas mucho... Si por ejemplo llegaras a chocar y el cuadrado rojo estuviera rodeado por obstáculos, ahí te quedarías... O si chocas con algo mientras estás en la fila o columna donde está el cuadrado azul, te quedarías ahí también...

Pero bueno, igual te da alguna idea para poder empezar.

Saludos!


Título: Re: Obtener ruta más corta
Publicado por: ecfisa en 15 Junio 2013, 00:54 am
Hola amchacon.

Lo que buscas se resuelve mediante teoría de grafos (https://es.wikipedia.org/wiki/teor%C3%ADa_de_grafos), en este enlace tenes una explicación genérica: grafos (http://www.algoritmia.net/articles.php?id=18).


Saludos.   :)


Título: Re: Obtener ruta más corta
Publicado por: OmarHack en 15 Junio 2013, 01:15 am
Puedes trazar todas las rutas posibles, y seleccionar las más cortas para usar en el programa.


Título: Re: Obtener ruta más corta
Publicado por: lapras en 15 Junio 2013, 01:47 am
El algoritmo de dijkstra te podria servir. O algo adaptado.


Título: Re: Obtener ruta más corta
Publicado por: amchacon en 15 Junio 2013, 12:16 pm
De hecho hay varias que son las más cortas. La que indicas es de 14 cuadrados, igual que por ejemplo, (2, 7) - (9, 7) - (9, 10) o (8, 2) - (8, 3) - (9, 3) - (9, 10), donde el primer número sería la fila y el segundo la columna.

Como primera aproximación, podrías intentar que el cuadrado rojo vaya alternativamente hacia la coordenada x e y del cuadrado azul. Es decir, primero intente ir hasta la coordenada x, si llega a la fila o columna donde está el azul o choca con algo que entonces intente ir hasta la y, si vuelve a chocar que vaya a la x, etc. y así hasta que llegue. En el ejemplo que pones, este algoritmo daría alguna de las soluciones que te he comentado arriba.

Igualmente es demasiado simple así que no le pidas mucho... Si por ejemplo llegaras a chocar y el cuadrado rojo estuviera rodeado por obstáculos, ahí te quedarías... O si chocas con algo mientras estás en la fila o columna donde está el cuadrado azul, te quedarías ahí también...

Pero bueno, igual te da alguna idea para poder empezar.

Saludos!
No me sirve, los obstaculos pueden estar dispuestos de cualquier forma... Prefiero un método genérico  :silbar:

Hola amchacon.

Lo que buscas se resuelve mediante teoría de grafos (https://es.wikipedia.org/wiki/teor%C3%ADa_de_grafos), en este enlace tenes una explicación genérica: grafos (http://www.algoritmia.net/articles.php?id=18).


Saludos.   :)

El algoritmo de busqueda en anchura es interesante   :)

El algoritmo de dijkstra te podria servir. O algo adaptado.
Pero aquí las distancias son iguales... No sé si vale la pena *_*


Título: Re: Obtener ruta más corta
Publicado por: lapras en 15 Junio 2013, 17:27 pm
Vale la pena por que el algoritmo de dijkstra es muy eficiente.
Te he hecho un programita en c++ que calcula el camino más corto entre dos celdas de un array.
Tienes obstaculos que se representan con un 1.

La función "getShortestPath" es la que lo hace todo y en el main lo que se hace es probar un ejemplo.

Código
  1. #include<iostream>
  2. #include<vector>
  3. #include<queue>
  4.  
  5. using namespace std;
  6.  
  7. class Cell{
  8. int x;
  9. int y;
  10. public:
  11. int getx(){return x;}
  12. int gety(){return y;}
  13. void setx(int x){this->x=x;}
  14. void sety(int y){this->y=y;}
  15.  
  16. bool operator==(Cell o){return x==o.x && y==o.y;}
  17. Cell operator=(Cell o){x=o.x; y=o.y; return *this;}
  18.  
  19. Cell(int x,int y):x(x),y(y){}
  20. Cell():x(0),y(0){}
  21. };
  22. vector<Cell> getShortestPath(Cell ori, Cell dest, int array[], int width, int height);
  23.  
  24.  
  25.  
  26. int main(){
  27. int ejemplo[]={
  28. 0,1,0,1,0,0,0,0, //0: void
  29. 0,1,0,1,0,0,0,0, //1: obstacle
  30. 0,1,0,1,0,0,0,0,
  31. 0,1,0,1,0,0,0,0,
  32. 0,1,0,1,0,0,0,0,
  33. 0,1,0,1,0,0,0,0,
  34. 0,0,0,1,0,0,0,0,
  35. 0,0,0,0,0,0,0,0};
  36.  
  37. vector<Cell> camino= getShortestPath(Cell(0,0),Cell(7,0),ejemplo,8,8);
  38. for(int i=0;i<camino.size();i++){
  39. cout<<"("<<camino[i].getx()<<", "<<camino[i].gety()<<")"<<endl;
  40. }
  41.  
  42. }
  43.  
  44. vector<Cell> getShortestPath(Cell ori, Cell dest, int array[], int width, int height){
  45.  
  46. if(ori==dest) return vector<Cell>();
  47. unsigned int *sizes=new unsigned int[width*height];
  48. Cell *prev=new Cell[width*height];
  49. for(int i=0;i<width*height;i++){sizes[i]=-1; prev[i]=Cell(-1,-1);}
  50.  
  51. sizes[ori.getx()+ori.gety()*width]=0;
  52. prev[ori.getx()+ori.gety()*width]=ori;
  53.  
  54.  
  55. queue<Cell> porVisitar;
  56. porVisitar.push(ori);
  57.  
  58. while(!porVisitar.empty()){
  59. Cell cur=porVisitar.front();
  60. porVisitar.pop();
  61. cout<<porVisitar.size()<<endl;
  62. for(int i=-1;i<2;i++)
  63. for(int j=-1;j<2;j++)
  64. if( (cur.getx()+j)>=0 && (cur.getx()+j)<width && (cur.gety()+i)>=0 && (cur.gety()+i)<height && //is not out of bounds
  65. array[(cur.getx()+j)+(cur.gety()+i)*width]==0 && //is not an obstable
  66. sizes[cur.getx()+cur.gety()*width]+1 < sizes[(cur.getx()+j)+(cur.gety()+i)*width] //there is not a better path
  67. ){
  68. sizes[(cur.getx()+j)+(cur.gety()+i)*width]=sizes[cur.getx()+cur.gety()*width]+1;
  69. prev[(cur.getx()+j)+(cur.gety()+i)*width]=Cell(cur.getx(),cur.gety());
  70. porVisitar.push(Cell(cur.getx()+j,cur.gety()+i));
  71. }
  72.  
  73. }
  74.  
  75. if(prev[dest.getx()+dest.gety()*width]==Cell(-1,-1)) return vector<Cell>();
  76.  
  77. Cell pp=dest;
  78. vector<Cell> res(sizes[dest.getx()+dest.gety()*width]+1);
  79. for(int i=res.size()-1; !(pp==ori); i--){
  80. res[i]=pp;
  81. pp=prev[pp.getx()+pp.gety()*width];
  82. }
  83.  
  84. return res;
  85.  
  86. }
  87.  

Lo que se hace es considerar que:
1) Toda celda del array es un nodo.
2) Todas las celdas estan conectadas a sus vecinas.
3) Todas las aristas son bidireccionales.
4) Todas las aristas miden lo mismo: 1.

Y con esto lo que se hace es implementar dijkstra en un caso particular más sencillo.

Te pongo un pastebin para que puedas copiar y pegar:
http://pastebin.com/unRpQgK5 (http://pastebin.com/unRpQgK5)


Título: Re: Obtener ruta más corta
Publicado por: amchacon en 15 Junio 2013, 21:07 pm
Muyy interesante  :o

Es todo lo que necesitaba gracias  ;-)