Floyd属于动态规划类计算最短路径的算法,通常的解法并不记录最短路径走法。笔者这里放一个带最短路径走法的Floyd算法。
c++代码如下
int findPairIDByPair(const QMap<int, QPoint>& ref, const QPoint& p)
{
auto itr = ref.begin();
while (itr != ref.end())
{
if (itr.value() == p)
return itr.key();
itr++;
}
return -1;
}
int floyd(const QList<QPoint>& vertices, const QList<QLine>& edges, const QPoint& from, const QPoint& to, QList<QPoint>& output)
{
if (!(vertices.contains(from) && vertices.contains(to)))
return -1;
QList<QPoint> points(vertices);
points.removeAll(from);
points.removeAll(to);
points.push_front(from);
points.push_back(to);
foreach(auto line,edges)
{
if (!points.contains(line.p1()))
return -1;
if (!points.contains(line.p2()))
return -1;
}
const int MAX_VALUE = std::numeric_limits<short>::max();
const int size = points.size();
QVector<boost::shared_array<QPair<int, int>>> ptr(size);
for (int i = 0; i < size; i++)
ptr[i].reset(new QPair<int, int>[size]);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
ptr[i][j].first = MAX_VALUE;
ptr[j][i].first = MAX_VALUE;
}
ptr[i][i].first = 0;
}
QMap<int, QPoint> ref;
for (int i = 0; i < size; i++)
ref[i] = points[i];
foreach(auto line, edges)
{
auto id1 = findPairIDByPair(ref, line.p1());
auto id2 = findPairIDByPair(ref, line.p2());
ptr[id1][id2].first = 1;
ptr[id2][id1].first = 1;
}
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
for (int k = 0; k < size; k++)
{
if (ptr[i][j].first > ptr[i][k].first + ptr[k][j].first)
{
ptr[i][j].second = k;
ptr[i][j].first = ptr[i][k].first + ptr[k][j].first;
}
}
if (ptr[0][size - 1].first >= MAX_VALUE)
return -1;
output.clear();
int i = size - 1;
output.append(ref[i]);
while (i != 0)
{
i = ptr[0][i].second;
output.append(ref[i]);
}
std::reverse(output.begin(), output.end());
return output.size() - 1;
}
函数int floyd(const QList<QPoint>& vertices, const QList<QLine>& edges, const QPoint& from, const QPoint& to, QList<QPoint>& output),参数分别是要计算点列表,边列表,起始和终止点,最短走点列表。
测试demo如下
class MinPath : public Scene
{
public:
MinPath();
~MinPath();
public:
void initGL();
void glDraw();
void qtDraw(QWidget* widget);
void update(int time);
public:
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void keyPressEvent(QKeyEvent* event);
private:
QFont font;
QPoint lastPos;
QList<QPoint> points;
QList<QPoint> drawPoints;
};
#define START QPoint(0,0)
#define END QPoint(16,11)
MinPath::MinPath()
{
}
MinPath::~MinPath()
{
}
void MinPath::initGL()
{
font.setPointSize(11);
QColor bgcolor(30,30,90,90);
World::getInstance().getGLPainter()->setBackgroundColor(bgcolor);
//auto vimage = QImage("tank.png");
/*texture = new QOpenGLTexture(vimage.mirrored());
texture->setMinificationFilter(QOpenGLTexture::Nearest);
texture->setMagnificationFilter(QOpenGLTexture::Linear);
texture->setWrapMode(QOpenGLTexture::Repeat);
texture->bind();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);*/
}
void MinPath::glDraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
auto painter = World::getInstance().getGLPainter();
glColor3f(0, 0, 0.3);
painter->drawHexGons(0, 0, World::getInstance().getWorldResolution(), 60, 64);
auto mgr = World::getInstance().getGridCellManager();
auto res = World::getInstance().getWorldResolution()*0.6;
painter->setLineWidth(2.0);
glColor3f(0.9, 0.2, 0.3);
auto p = mgr->getWorldPosByCellCoordinate(START.x(), START.y());
painter->drawHexGon(p.x(), p.y(), res*0.6);
p = mgr->getWorldPosByCellCoordinate(END.x(), END.y());
painter->drawHexGon(p.x(), p.y(), res*0.6);
glColor3f(0.6, 0.1, 0.1);
foreach(auto item, points)
{
p = mgr->getWorldPosByCellCoordinate(item.x(), item.y());
painter->drawWrongNumber(p, res);
}
glColor3f(0.1, 0.6, 0.2);
int count = drawPoints.size();
if (count > 0)
{
for (int i = 0; i < count - 1; i++)
{
auto p1 = mgr->getWorldPosByCellCoordinate(drawPoints[i].x(),drawPoints[i].y());
auto p2 = mgr->getWorldPosByCellCoordinate(drawPoints[i+1].x(), drawPoints[i+1].y());
painter->drawLine(p1,p2);
}
}
painter->setLineWidth(1.0);
glPopMatrix();
}
void MinPath::qtDraw(QWidget* widget)
{
QPainter pter(widget);
pter.setPen(QColor(30,120,90));
pter.setFont(font);
pter.drawText(8,20,QStringLiteral("鼠标左键设置和取消障碍,空格键计算最短路径"));
pter.end();
}
void MinPath::update(int time)
{
}
void MinPath::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::MouseButton::RightButton)
{
return;
}
lastPos = event->pos();
int height = World::getInstance().getWorldSize().height();
auto pos = World::getInstance().getGridCellManager()->getCellCoordinateByWorldPos(lastPos.x(), height - lastPos.y());
if (pos == START || pos == END)
return;
auto itr = qFind(points, pos);
if (itr == points.end())
points.push_back(pos);
else
{
std::remove(points.begin(), points.end(), pos);
}
}
void MinPath::mouseMoveEvent(QMouseEvent* event)
{
}
void MinPath::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key::Key_Space)
{
auto edges = World::getInstance().getGridCellManager()->getAdjacentCellsInMap(END.x(), END.y(), points);
QList<QPoint> allPoints;
for (int i = 0; i <= END.x(); i++)
for (int j = 0; j <= END.y(); j++)
{
allPoints.append(QPoint(i, j));
}
int cnt = floyd(allPoints, edges, START, END, drawPoints);
if (cnt == -1)
drawPoints.clear();
}
}
显示截图如下
![e0e62a9529aa640ec6fdc8c9347ebaa3.png](https://i-blog.csdnimg.cn/blog_migrate/e5cf3016893c3f8e3ef47682e6e11949.jpeg)
![f62998373c856b5d935f8990b945d8c5.png](https://i-blog.csdnimg.cn/blog_migrate/0187b3a1eb0a945a66c86f47da7957bd.jpeg)
如果需要完整代码请联系本人~