目录
题目:
答:
1建立数学模型
2求解
题目:
一个简易吃豆人游戏,假设有一个m*n的棋盘(0
答:
解答本题分如下两步:1建立数学模型;2求解。
1建立数学模型
将这个m*n的棋盘(左图)抽象为图论中的有向无环图(缩写为DAG,右图)。

棋盘中的每个格子对应有向无环图的一个顶点,指向该顶点的边的权重等于该顶点的豆子数(比如,指向棋盘格子b的边,权重等于b,以此类推)。由于吃豆人只能向右或者向下移动,所以水平方向的边只能从左向右,垂直方向的边只能从上到下,如上图所示。由于这个限制,导致从任何一点出发,不论采取何种路径,都不会回到出发点,所以这个图是无环图。
由于棋盘中的每个格子对应有向无环图的一个顶点,所以有向无环图的水平方向的顶点数等于棋盘水平方向的格子数m,而水平方向的边数比顶点数少1,所以是m-1;有向无环图的垂直方向的顶点数等于棋盘垂直方向的格子数n,所以有向无环图的垂直方向的顶点数是n,垂直方向的边数是n-1。顶点总数为m*n。而边总数为(m-1)*(n-1)。
搜索吃豆人吃豆最多路线的问题就变成了搜索DAG最长路径的问题。此类问题的复杂度是O(边数+顶点数),故为O(m*n)
2求解
Longest Path in a Directed Acyclic Graph - GeeksforGeeks提供了示例代码解决此类问题。在此示例基础上略作修改,考虑如下棋盘,其格子中的数字代表格子内豆子数目:
根据前面的分析,数学模型对应一个顶点数为4 * 3= 12的DAG。
采用如下代码求解:
AdjListNode(int _v, int _w)
int getWeight() { return weight; }
void topologicalSortUtil(int v, bool visited[],
void addEdge(int u, int v, int weight);
pPath = new list<int>[V];
void Graph::addEdge(int u, int v, int weight)
AdjListNode node(v, weight);
void Graph::topologicalSortUtil(int v, bool visited[],
for (i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[node.getV()])
topologicalSortUtil(node.getV(), visited, Stack);
void Graph::longestPath(int s)
bool* visited = new bool[V];
for (int i = 0; i < V; i++)
for (int i = 0; i < V; i++)
topologicalSortUtil(i, visited, Stack);
for (int i = 0; i < V; i++)
while (Stack.empty() == false) {
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (dist[i->getV()] < dist[u] + i->getWeight())
dist[i->getV()] = dist[u] + i->getWeight();
pPath[i->getV()].assign(pPath[u].begin(), pPath[u].end());
pPath[i->getV()].push_back(i->getV());
for (int i = 0; i < V; i++)
(dist[i] == NINF) ? cout << "unReachable" : cout << dist[i];
for (const auto & item : pPath[i])
cout << "Following are longest distances from "

在上面的问题中,采用0-11标记棋盘的格子:
结果:

可见,最长路径是0-4-5-9-10-11,长度为14
算法的时间复杂度为O(顶点数+边数)。这里也就是O(m*n)