以前做了个什么网络计划的算法,昨天拿来一看,好像还有问题,早上过来,弄了下,加了注释,和调试信息输出的功能,方便理解,我调试了下,没发现什么问题,如果大家发现的话,请告诉我,谢谢。
由于程序是没人那么聪明的,只有遍历了。
首先,两点之间加上中间那条线,用个类保存,类说明了这段路程的三个基本属性:起始点、结束点、需要时间,剩下的五个附加属性是遍历的时候要用到的:skip、hasFrontNode、eNodeIsBranchEndNode、sNodeIsBranchEndNode、sNodeIsBranchBeginNode,skip说明这段是否已经走过, hasFrontNode说明是否还有前驱节点,eNodeIsBranchEndNode说明这段路程的尾节点是否有多个前驱,sNodeIsBranchBeginNode是头节点是否有多个后继。
首先,将所有路程信息用个数组保存起来。addProcessInfo(int sNode,int eNode,int lTime)是将一段路程的基本信息保存,setup()加入多段具体的路程信息,然后setNodeTag() 为每段路程信息的附加属性赋值。
最主要的就在searchProcess(int sNode,int eNode)函数了,这是求任意两点间的,理论上来说,顺着找和倒着找是一样的,但是为了这个项目,我用的是倒着找的,因为要的是开始点到某个点的,顺着找的话,会走好多冤枉路,倒着的话,由于起点就一个,一般可以直接找到,而不会走过去了。
下面说说这段函数的原理:
找路径,好比人走路,找最优路径,需要走遍所有的路才能知道。一开始,看看所处的位置可以有几条路,都记下来,然后,每次挑一条可以走的路,走下去,走到走不动的地方,往回走,直到回到上个叉路口,如果回到起点,只能说明,没路了.....否则,就从后退到的那个路口继续那样的找路过程。走到终点后,记下这条路,然后,回到上个叉路口,继续走,又到终点,比比原来记下来的路,看哪条好,去掉不好的。一直就这么找,直到你走完所有的可能,才可能得到最优的解。
找一个点到另一个点的最优路径,对于程序来说,问题就在于怎么保存走过的路,应该怎么保存,保存的是什么内容。由于我是倒着找的,所以在这段代码中,我保存的是new ProcessInfo(sNode, eNode,pInfo.lastingTime),实际上是不存在这样的路径的,只是为了方便回溯保存的,然后,递归找开始节点到当前路径的开始节点间的路径。
下面我把代码贴出来,再附加二个调试信息,方便大家理解,关于那个网络图的定义可以在setup()函数中修改。
首先是保存路径信息的类(ProcessInfo.java):
由于程序是没人那么聪明的,只有遍历了。
首先,两点之间加上中间那条线,用个类保存,类说明了这段路程的三个基本属性:起始点、结束点、需要时间,剩下的五个附加属性是遍历的时候要用到的:skip、hasFrontNode、eNodeIsBranchEndNode、sNodeIsBranchEndNode、sNodeIsBranchBeginNode,skip说明这段是否已经走过, hasFrontNode说明是否还有前驱节点,eNodeIsBranchEndNode说明这段路程的尾节点是否有多个前驱,sNodeIsBranchBeginNode是头节点是否有多个后继。
首先,将所有路程信息用个数组保存起来。addProcessInfo(int sNode,int eNode,int lTime)是将一段路程的基本信息保存,setup()加入多段具体的路程信息,然后setNodeTag() 为每段路程信息的附加属性赋值。
最主要的就在searchProcess(int sNode,int eNode)函数了,这是求任意两点间的,理论上来说,顺着找和倒着找是一样的,但是为了这个项目,我用的是倒着找的,因为要的是开始点到某个点的,顺着找的话,会走好多冤枉路,倒着的话,由于起点就一个,一般可以直接找到,而不会走过去了。
下面说说这段函数的原理:
找路径,好比人走路,找最优路径,需要走遍所有的路才能知道。一开始,看看所处的位置可以有几条路,都记下来,然后,每次挑一条可以走的路,走下去,走到走不动的地方,往回走,直到回到上个叉路口,如果回到起点,只能说明,没路了.....否则,就从后退到的那个路口继续那样的找路过程。走到终点后,记下这条路,然后,回到上个叉路口,继续走,又到终点,比比原来记下来的路,看哪条好,去掉不好的。一直就这么找,直到你走完所有的可能,才可能得到最优的解。
找一个点到另一个点的最优路径,对于程序来说,问题就在于怎么保存走过的路,应该怎么保存,保存的是什么内容。由于我是倒着找的,所以在这段代码中,我保存的是new ProcessInfo(sNode, eNode,pInfo.lastingTime),实际上是不存在这样的路径的,只是为了方便回溯保存的,然后,递归找开始节点到当前路径的开始节点间的路径。
下面我把代码贴出来,再附加二个调试信息,方便大家理解,关于那个网络图的定义可以在setup()函数中修改。
首先是保存路径信息的类(ProcessInfo.java):
1/**
2 * @author zxub Created on 2005-5-21 10:36:29
3 *
4 */
5public class ProcessInfo {
6
7 //基本信息:startNode,endNode,lastingTime
8 protected int startNode; //开始节点
9 protected int endNode; //终止节点
10 protected int lastingTime; //路径持续时间
11 //下面是附加信息,遍历的时候用到
12 protected boolean skip; //判断该路径是否已经走过
13 protected boolean hasFrontNode; //路径是否有前驱节点
14 protected boolean eNodeIsBranchEndNode; //路径终止节点是否有多个前驱
15 protected boolean sNodeIsBranchBeginNode; //路径开始节点是否有多个后继
16
17 /**
18 * 保存任意两点间路径信息
19 * @param sNode 开始节点
20 * @param eNode 终止节点
21 * @param lTime 持续时间
22 */
23 public ProcessInfo(int sNode,int eNode,int lTime)
24 {
25 this.startNode=sNode;
26 this.endNode=eNode;
27 this.lastingTime=lTime;
28 //由于是刚开始保存,下面的几个信息不能确立,所以都是false
29 this.skip=false;
30 this.hasFrontNode=false;
31 this.eNodeIsBranchEndNode=false;
32 this.sNodeIsBranchBeginNode=false;
33 }
34}
然后,是主要的处理类(ProcessOpera.java):2 * @author zxub Created on 2005-5-21 10:36:29
3 *
4 */
5public class ProcessInfo {
6
7 //基本信息:startNode,endNode,lastingTime
8 protected int startNode; //开始节点
9 protected int endNode; //终止节点
10 protected int lastingTime; //路径持续时间
11 //下面是附加信息,遍历的时候用到
12 protected boolean skip; //判断该路径是否已经走过
13 protected boolean hasFrontNode; //路径是否有前驱节点
14 protected boolean eNodeIsBranchEndNode; //路径终止节点是否有多个前驱
15 protected boolean sNodeIsBranchBeginNode; //路径开始节点是否有多个后继
16
17 /**
18 * 保存任意两点间路径信息
19 * @param sNode 开始节点
20 * @param eNode 终止节点
21 * @param lTime 持续时间
22 */
23 public ProcessInfo(int sNode,int eNode,int lTime)
24 {
25 this.startNode=sNode;
26 this.endNode=eNode;
27 this.lastingTime=lTime;
28 //由于是刚开始保存,下面的几个信息不能确立,所以都是false
29 this.skip=false;
30 this.hasFrontNode=false;
31 this.eNodeIsBranchEndNode=false;
32 this.sNodeIsBranchBeginNode=false;
33 }
34}
1import java.util.Stack;
2
3/**
4 * @author zxub Created on 2005-5-22 10:19:51
5 */
6public class ProcessOpera
7{
8
9 final int MAX = 100;
10 // 保存路径信息的数组
11 ProcessInfo process[] = new ProcessInfo[MAX];
12 // 保存路径数目
13 int numProcess = 0;
14 // 分支路径栈
15 Stack branchProcessStack = new Stack();
16 // 用于搜索回退的栈
17 Stack backTrackStack = new Stack();
18 // 保存最后结果的栈
19 Stack resultStack = new Stack();
20 // 最长持续时间
21 int maxLastingTime = 0;
22
23 /**
24 * 测试用
25 *
26 * @param args
27 */
28 public static void main(String[] args)
29 {
30
31 ProcessOpera processOpera = new ProcessOpera();
32 processOpera.setup();
33 processOpera.setNodeTag();
34// for (int i = 0; i < processOpera.numProcess; i++)
35// {
36// System.out.print(processOpera
37// .getItemEarliestBeginTime(processOpera.process[i].startNode)
38// + " ");
39// System.out.print(processOpera.getProcessEarliestEndTime(
40// processOpera.process[i].startNode,
41// processOpera.process[i].endNode)
42// + " ");
43// System.out.print(processOpera.getProcessEarliestBeginTime(
44// processOpera.process[i].startNode,
45// processOpera.process[i].endNode)
46// + " ");
47// System.out.print(processOpera
48// .getItemLatestEndTime(processOpera.process[i].startNode)
49// + " ");
50// System.out.print(processOpera.getProcessLatestBeginTime(
51// processOpera.process[i].startNode,
52// processOpera.process[i].endNode)
53// + " ");
54// System.out.print(processOpera.getProcessLatestEndTime(
55// processOpera.process[i].startNode,
56// processOpera.process[i].endNode)
57// + " ");
58// System.out.print(processOpera.getProcessIntervalTime(
59// processOpera.process[i].startNode,
60// processOpera.process[i].endNode)
61// + " ");
62// System.out.print(processOpera.getKeyPath(
63// processOpera.process[i].startNode,
64// processOpera.process[i].endNode)
65// + " ");
66// System.out.println();
67// }
68//
69// System.out.println(processOpera.getItemEarliestBeginTime(1));
70 processOpera.searchProcess(2, 8, 0);
71 processOpera.showPath();
72 }
73
74 /**
75 * 初始化所有路径信息,放进数组中
76 */
77 public void setup()
78 {
79 addProcessInfo(1, 2, 60);
80 addProcessInfo(2, 3, 10);
81 addProcessInfo(2, 4, 20);
82 addProcessInfo(2, 5, 40);
83 addProcessInfo(2, 7, 45);
84 addProcessInfo(3, 7, 18);
85 addProcessInfo(4, 5, 0);
86 addProcessInfo(4, 6, 30);
87 addProcessInfo(5, 7, 15);
88 addProcessInfo(6, 7, 25);
89 addProcessInfo(7, 8, 35);
90 addProcessInfo(8, 8, 0);
91 }
92
93 /**
94 * 增加路径信息到数组中
95 *
96 * @param sNode
97 * 开始节点
98 * @param eNode
99 * 终止节点
100 * @param lTime
101 * 持续时间
102 */
103 public void addProcessInfo(int sNode, int eNode, int lTime)
104 {
105 if (numProcess < MAX) // 如果数组没满的话
106 {
107 process[numProcess] = new ProcessInfo(sNode, eNode, lTime);
108 numProcess++;
109 }
110 else
111 {
112 System.out
113 .println("ProcessInfo database full!\nAdd error,program exit!");
114 System.exit(0);
115 }
116 }
117
118 /**
119 * 给所有路径信息中的附加属性赋值,要完成的话,需要遍历路径数组中的所有元素。 对于每个元素,要查看数组中的其它元素,确立关系
120 */
121 public void setNodeTag()
122 {
123 for (int i = 0; i < numProcess; i++) // 遍历路径数组中的所有元素,process[i]是选取的路径
124 {
125 for (int j = 0; j < numProcess; j++) // 查看其它元素
126 {
127 if (i == j) continue; // 自己比自己,没得比,继续下次循环
128 // 发现有路径可以和选取路径连接
129 if (process[j].endNode == process[i].startNode)
130 {
131 process[i].hasFrontNode = true;
132 }
133 // 两条不同路径的终结点一样
134 if (process[j].endNode == process[i].endNode)
135 {
136 process[i].eNodeIsBranchEndNode = true;
137 }
138 // 两条不同路径的起始点一样
139 if (process[j].startNode == process[i].startNode)
140 {
141 process[i].sNodeIsBranchBeginNode = true;
142 }
143 }
144 }
145 }
146
147 /**
148 * 找出以选取点为终结点的没走过的一条路径
149 *
150 * @param eNode
151 * 所选取的点
152 * @return 没被走过的以选取点为终结点的一条路径
153 */
154 public ProcessInfo findProcessInfo(int eNode)
155 {
156 for (int i = 0; i < numProcess; i++) // 遍历路径信息
157 {
158 // process[i].skip=false 路径才没被走过
159 if ((process[i].endNode == eNode) && (!process[i].skip))
160 {
161 // 由于深度复制和浅度复制的问题,所以复制的时候要新建一个ProcessInfo,而不是引用原来
162 // 这是实现问题,算法与此可以无关
163 ProcessInfo pInfo = new ProcessInfo(process[i].startNode,
164 process[i].endNode, process[i].lastingTime);
165 process[i].skip = true;
166 pInfo.hasFrontNode = process[i].hasFrontNode;
167 pInfo.eNodeIsBranchEndNode = process[i].eNodeIsBranchEndNode;
168 return pInfo;
169 }
170 }
171 return null; // 没有合适的路径就返回null了
172 }
173
174 /**
175 * 核心部分所在,查找任意2点间最长路径 基于AI设计,简单的AI 理论上来说,顺着找和倒着找是一样的,由于项目原因,这里我是倒着找的
176 * 查找到的路径放在结果栈resultStack中
177 *
178 * @param sNode
179 * 开始节点
180 * @param eNode
181 * 终止节点
182 * @param depth
183 * 显示debug信息的时候用到,用于显示层次关系
184 */
185 public void searchProcess(int sNode, int eNode, int depth)
186 {
187 // 变量定义尽量少放循环中,故先定义
188 int lastingTime; // 持续时间
189 ProcessInfo pInfo; // 保存路径信息的对象
190 int numStartNode = 0; // 查找起点的个数
191 Stack resultTemp; // 保存查找到路径的临时栈
192 while ((pInfo = findProcessInfo(eNode)) != null)
193 {
194 // 分支节点数目+1
195 numStartNode++;
196 // 将查找到的路径信息放到分支节点栈,然后再查
197 branchProcessStack.push(pInfo);
198 showDebugInfo("分支路径栈加入:" + pInfo.startNode + "-->" + pInfo.endNode,
199 depth);
200 }
201 if (numStartNode > 0) // 有分支的话,如果这里不成立,整个就结束了
202 {
203 for (int i = 0; i < numStartNode; i++) // 遍历分支节点栈
204 {
205 pInfo = (ProcessInfo) branchProcessStack.pop(); // 获得一条分支路径
206 showDebugInfo("分支路径栈弹出:" + pInfo.startNode + "-->"
207 + pInfo.endNode, depth);
208 // 为了防止头尾一样的路径,有了下面的判断,理论上是没有,但实际会出现
209 if (pInfo.startNode == pInfo.endNode)
210 {
211 showDebugInfo("头尾节点一样,丢弃!", depth + 1);
212 continue;
213 }
214
215 // 如果存在可到达的路径的话,注意,这是个递归过程
216 if (pInfo.startNode == sNode)
217 {
218 // 当前路径加入回退栈,此时,回退栈里可以找出一条完整的路径了
219 backTrackStack.push(pInfo);
220 showDebugInfo("--------到达起点:" + pInfo.startNode + "-->"
221 + pInfo.endNode + "--------", depth);
222 int numbackTrackStack = backTrackStack.size();
223 resultTemp = new Stack();
224 lastingTime = 0;
225 for (int j = 0; j < numbackTrackStack; j++)
226 {
227 pInfo = (ProcessInfo) backTrackStack.get(j);
228 showDebugInfo("回溯栈内容进入临时结果栈:" + pInfo.startNode + "-->"
229 + pInfo.endNode, depth);
230 lastingTime += pInfo.lastingTime;
231 resultTemp.push(pInfo);
232 }
233 // 判断是不是更好的解
234 if (lastingTime > maxLastingTime)
235 {
236 showDebugInfo("========找到更优解!========", depth);
237 maxLastingTime = lastingTime;
238 resultStack = resultTemp;
239 }
240 // 找出一条后,需要回退,然后继续找下一条
241 // 获得剩余分支路径的数目
242 int numBranch = branchProcessStack.size();
243
244 if (numBranch == 0)
245 {
246 // 没分支路径了,查找结束,清空回退栈
247 backTrackStack.removeAllElements();
248 }
249 else if (numBranch > 0)
250 {
251 int index = numBranch - 1;
252 int backTrackValue = ((ProcessInfo) branchProcessStack
253 .get(index)).endNode;
254 showDebugInfo("--------回退到节点:" + backTrackValue
255 + "--------", depth);
256 // 要回退到的节点必是分支路径栈中最上路径的尾节点
257 // 下面的循环就是一直回退,由于还有分支路径,所以可以找到要退到的点
258 do
259 {
260 pInfo = (ProcessInfo) backTrackStack.pop();
261 showDebugInfo("找到目标,回溯栈回退到:" + pInfo.startNode
262 + "-->" + pInfo.endNode, depth);
263 }
264 while (pInfo.endNode != backTrackValue);
265 }
266 // 回退后,继续查找的话,所有路径的经过标记都要重置,否则经过了的路径是不会再去查的
267 // 由于开始路径不同,所以不会找到同样的结果
268 resetAllSkip();
269 continue;// 开始从下个分支路径查找
270 }
271 else
272 // 没有直接从sNode到eNode的工序
273 {
274 // 还没到目标
275 // 如果当前路径的起点还有前驱节点的话,需要递归查找,这是重点
276 if (pInfo.hasFrontNode)
277 {
278 ProcessInfo btPInfo = new ProcessInfo(sNode, eNode,
279 pInfo.lastingTime);
280 btPInfo.eNodeIsBranchEndNode = pInfo.eNodeIsBranchEndNode;
281 // 说明找过sNode-->eNode
282 backTrackStack.push(btPInfo);
283 showDebugInfo("回溯栈加入:" + sNode + "-->" + eNode
284 + ",说明找过" + sNode + "-->" + eNode, depth + 1);
285 showDebugInfo("查找:" + sNode + "-->" + pInfo.startNode,
286 depth + 1);
287 searchProcess(sNode, pInfo.startNode, depth + 2);
288 }
289 else
290 // 当前路径的起点无前驱,则路径错误,需要回溯
291 {
292 // 如果当前路径的终结点还有其它前驱的话,则退出本次循环,从下个分支路径查找
293 if (pInfo.eNodeIsBranchEndNode)
294 {
295 continue;
296 }
297 // 如果当前路径的终结点没有其它前驱,就要回退了
298 else if (backTrackStack.size() > 0)
299 {
300 // 开始回退,一直到找到个路径的终止节点有多个前驱为止,或者是回退栈已经空了。
301 do
302 {
303 pInfo = (ProcessInfo) backTrackStack.pop();
304 showDebugInfo("路径错误,开始回溯,回溯栈弹出:"
305 + pInfo.startNode + "-->"
306 + pInfo.endNode, depth + 1);
307 }
308 while ((!pInfo.eNodeIsBranchEndNode)
309 && (backTrackStack.size() > 0));
310 }
311 }
312 }
313 }
314 showDebugInfo("分支已被找遍", depth);
315 }
316 else
317 {
318 showDebugInfo("前面已走过这条路径且被证明走不通,或尾节点没有前驱节点", depth);
319 if (backTrackStack.size()>0)
320 {
321 pInfo = (ProcessInfo) backTrackStack.pop();
322 showDebugInfo("路径不通,回溯栈弹出:" + pInfo.startNode + "-->"
323 + pInfo.endNode, depth - 1);
324 if (branchProcessStack.size()>0)
325 {
326 int fixNode = ((ProcessInfo) branchProcessStack.lastElement()).endNode;
327 if (fixNode != pInfo.endNode)
328 {
329 showDebugInfo("========需要调整回溯栈========", depth);
330 showDebugInfo("========开始调整回溯栈========", depth);
331 do
332 {
333 pInfo = (ProcessInfo) backTrackStack.pop();
334 showDebugInfo("回溯栈弹出:" + pInfo.startNode + "-->"
335 + pInfo.endNode, depth + 1);
336 }
337 while (fixNode != pInfo.endNode);
338 showDebugInfo("========回溯栈调整结束========", depth);
339 }
340 }
341 }
342 }
343 }
344
345 private void showDebugInfo(String info, int blankCount)
346 {
347 String blank = "";
348 for (int i = 0; i < blankCount; i++)
349 {
350 blank += " ";
351 }
352 System.out.println(blank + info);
353 }
354
355 public int getLastingTime(int sNode, int eNode)
356 {
357 int lastingTime = 0;
358 ProcessInfo pInfo;
359 searchProcess(sNode, eNode, 0);
360 int num = resultStack.size();
361 for (int i = num - 1; i >= 0; i--)
362 {
363 pInfo = (ProcessInfo) resultStack.get(i);
364 lastingTime += pInfo.lastingTime;
365 }
366 return lastingTime;
367 }
368
369 public void showPath()
370 {
371 ProcessInfo pInfo;
372 int num = resultStack.size();
373 if (num==0)
374 {
375 showDebugInfo("========没有符合要求的路径========",0);
376 }
377 else
378 {
379 for (int i = 0; i < num; i++)
380 {
381 pInfo = (ProcessInfo) resultStack.pop();
382 System.out.print("-->" + pInfo.endNode);
383 }
384 }
385 }
386
387 public void resetAllSkip()
388 {
389 for (int i = 0; i < numProcess; i++)
390 {
391 process[i].skip = false;
392 }
393 }
394
395 public int getItemEarliestBeginTime(int itemIndex)
396 {
397 maxLastingTime = 0;
398 backTrackStack.removeAllElements();
399 resultStack.removeAllElements();
400 return getLastingTime(1, itemIndex);
401 }
402
403 public int getProcessEarliestEndTime(int sNode, int eNode)
404 {
405 for (int i = 0; i < numProcess; i++)
406 {
407 if ((process[i].startNode == sNode)
408 && (process[i].endNode == eNode))
409 {
410 return (getItemEarliestBeginTime(sNode) + process[i].lastingTime);
411 }
412 }
413 return 0;
414 }
415
416 public int getProcessEarliestBeginTime(int sNode, int eNode)
417 {
418 return (getItemEarliestBeginTime(sNode));
419 }
420
421 public int getItemLatestEndTime(int itemIndex)
422 {
423 int maxTime = 0;
424 int t = 0;
425 int pos = -1;
426 boolean hasNextNode = false;
427 backTrackStack.removeAllElements();
428 resultStack.removeAllElements();
429 for (int i = 0; i < numProcess; i++)
430 {
431 if (process[i].startNode == itemIndex)
432 {
433 if (process[i].sNodeIsBranchBeginNode)
434 {
435 return (getItemEarliestBeginTime(itemIndex));
436 }
437 hasNextNode = true;
438 t = getItemEarliestBeginTime(process[i].endNode);
439 if (t > maxTime)
440 {
441 pos = i;
442 maxTime = t;
443 }
444 }
445 }
446 if (!hasNextNode)
447 {
448 return (getItemEarliestBeginTime(itemIndex));
449 }
450 else
451 {
452 return (t - process[pos].lastingTime);
453 }
454 }
455
456 public int getProcessLatestEndTime(int sNode, int eNode)
457 {
458 return (getItemLatestEndTime(eNode));
459 }
460
461 public int getProcessLatestBeginTime(int sNode, int eNode)
462 {
463 for (int i = 0; i < numProcess; i++)
464 {
465 if ((process[i].startNode == sNode)
466 && (process[i].endNode == eNode))
467 {
468 return (getProcessLatestEndTime(sNode, eNode) - process[i].lastingTime);
469 }
470 }
471 return 0;
472 }
473
474 public int getProcessIntervalTime(int sNode, int eNode)
475 {
476 return (getProcessLatestEndTime(sNode, eNode) - getProcessEarliestEndTime(
477 sNode, eNode));
478 }
479
480 public int getKeyPath(int sNode, int eNode)
481 {
482 if ((getProcessIntervalTime(sNode, eNode) == 0) && (sNode != eNode))
483 {
484 return eNode;
485 }
486 else
487 {
488 return 0;
489 }
490 }
491}
最后是调试信息(找2到8):2
3/**
4 * @author zxub Created on 2005-5-22 10:19:51
5 */
6public class ProcessOpera
7{
8
9 final int MAX = 100;
10 // 保存路径信息的数组
11 ProcessInfo process[] = new ProcessInfo[MAX];
12 // 保存路径数目
13 int numProcess = 0;
14 // 分支路径栈
15 Stack branchProcessStack = new Stack();
16 // 用于搜索回退的栈
17 Stack backTrackStack = new Stack();
18 // 保存最后结果的栈
19 Stack resultStack = new Stack();
20 // 最长持续时间
21 int maxLastingTime = 0;
22
23 /**
24 * 测试用
25 *
26 * @param args
27 */
28 public static void main(String[] args)
29 {
30
31 ProcessOpera processOpera = new ProcessOpera();
32 processOpera.setup();
33 processOpera.setNodeTag();
34// for (int i = 0; i < processOpera.numProcess; i++)
35// {
36// System.out.print(processOpera
37// .getItemEarliestBeginTime(processOpera.process[i].startNode)
38// + " ");
39// System.out.print(processOpera.getProcessEarliestEndTime(
40// processOpera.process[i].startNode,
41// processOpera.process[i].endNode)
42// + " ");
43// System.out.print(processOpera.getProcessEarliestBeginTime(
44// processOpera.process[i].startNode,
45// processOpera.process[i].endNode)
46// + " ");
47// System.out.print(processOpera
48// .getItemLatestEndTime(processOpera.process[i].startNode)
49// + " ");
50// System.out.print(processOpera.getProcessLatestBeginTime(
51// processOpera.process[i].startNode,
52// processOpera.process[i].endNode)
53// + " ");
54// System.out.print(processOpera.getProcessLatestEndTime(
55// processOpera.process[i].startNode,
56// processOpera.process[i].endNode)
57// + " ");
58// System.out.print(processOpera.getProcessIntervalTime(
59// processOpera.process[i].startNode,
60// processOpera.process[i].endNode)
61// + " ");
62// System.out.print(processOpera.getKeyPath(
63// processOpera.process[i].startNode,
64// processOpera.process[i].endNode)
65// + " ");
66// System.out.println();
67// }
68//
69// System.out.println(processOpera.getItemEarliestBeginTime(1));
70 processOpera.searchProcess(2, 8, 0);
71 processOpera.showPath();
72 }
73
74 /**
75 * 初始化所有路径信息,放进数组中
76 */
77 public void setup()
78 {
79 addProcessInfo(1, 2, 60);
80 addProcessInfo(2, 3, 10);
81 addProcessInfo(2, 4, 20);
82 addProcessInfo(2, 5, 40);
83 addProcessInfo(2, 7, 45);
84 addProcessInfo(3, 7, 18);
85 addProcessInfo(4, 5, 0);
86 addProcessInfo(4, 6, 30);
87 addProcessInfo(5, 7, 15);
88 addProcessInfo(6, 7, 25);
89 addProcessInfo(7, 8, 35);
90 addProcessInfo(8, 8, 0);
91 }
92
93 /**
94 * 增加路径信息到数组中
95 *
96 * @param sNode
97 * 开始节点
98 * @param eNode
99 * 终止节点
100 * @param lTime
101 * 持续时间
102 */
103 public void addProcessInfo(int sNode, int eNode, int lTime)
104 {
105 if (numProcess < MAX) // 如果数组没满的话
106 {
107 process[numProcess] = new ProcessInfo(sNode, eNode, lTime);
108 numProcess++;
109 }
110 else
111 {
112 System.out
113 .println("ProcessInfo database full!\nAdd error,program exit!");
114 System.exit(0);
115 }
116 }
117
118 /**
119 * 给所有路径信息中的附加属性赋值,要完成的话,需要遍历路径数组中的所有元素。 对于每个元素,要查看数组中的其它元素,确立关系
120 */
121 public void setNodeTag()
122 {
123 for (int i = 0; i < numProcess; i++) // 遍历路径数组中的所有元素,process[i]是选取的路径
124 {
125 for (int j = 0; j < numProcess; j++) // 查看其它元素
126 {
127 if (i == j) continue; // 自己比自己,没得比,继续下次循环
128 // 发现有路径可以和选取路径连接
129 if (process[j].endNode == process[i].startNode)
130 {
131 process[i].hasFrontNode = true;
132 }
133 // 两条不同路径的终结点一样
134 if (process[j].endNode == process[i].endNode)
135 {
136 process[i].eNodeIsBranchEndNode = true;
137 }
138 // 两条不同路径的起始点一样
139 if (process[j].startNode == process[i].startNode)
140 {
141 process[i].sNodeIsBranchBeginNode = true;
142 }
143 }
144 }
145 }
146
147 /**
148 * 找出以选取点为终结点的没走过的一条路径
149 *
150 * @param eNode
151 * 所选取的点
152 * @return 没被走过的以选取点为终结点的一条路径
153 */
154 public ProcessInfo findProcessInfo(int eNode)
155 {
156 for (int i = 0; i < numProcess; i++) // 遍历路径信息
157 {
158 // process[i].skip=false 路径才没被走过
159 if ((process[i].endNode == eNode) && (!process[i].skip))
160 {
161 // 由于深度复制和浅度复制的问题,所以复制的时候要新建一个ProcessInfo,而不是引用原来
162 // 这是实现问题,算法与此可以无关
163 ProcessInfo pInfo = new ProcessInfo(process[i].startNode,
164 process[i].endNode, process[i].lastingTime);
165 process[i].skip = true;
166 pInfo.hasFrontNode = process[i].hasFrontNode;
167 pInfo.eNodeIsBranchEndNode = process[i].eNodeIsBranchEndNode;
168 return pInfo;
169 }
170 }
171 return null; // 没有合适的路径就返回null了
172 }
173
174 /**
175 * 核心部分所在,查找任意2点间最长路径 基于AI设计,简单的AI 理论上来说,顺着找和倒着找是一样的,由于项目原因,这里我是倒着找的
176 * 查找到的路径放在结果栈resultStack中
177 *
178 * @param sNode
179 * 开始节点
180 * @param eNode
181 * 终止节点
182 * @param depth
183 * 显示debug信息的时候用到,用于显示层次关系
184 */
185 public void searchProcess(int sNode, int eNode, int depth)
186 {
187 // 变量定义尽量少放循环中,故先定义
188 int lastingTime; // 持续时间
189 ProcessInfo pInfo; // 保存路径信息的对象
190 int numStartNode = 0; // 查找起点的个数
191 Stack resultTemp; // 保存查找到路径的临时栈
192 while ((pInfo = findProcessInfo(eNode)) != null)
193 {
194 // 分支节点数目+1
195 numStartNode++;
196 // 将查找到的路径信息放到分支节点栈,然后再查
197 branchProcessStack.push(pInfo);
198 showDebugInfo("分支路径栈加入:" + pInfo.startNode + "-->" + pInfo.endNode,
199 depth);
200 }
201 if (numStartNode > 0) // 有分支的话,如果这里不成立,整个就结束了
202 {
203 for (int i = 0; i < numStartNode; i++) // 遍历分支节点栈
204 {
205 pInfo = (ProcessInfo) branchProcessStack.pop(); // 获得一条分支路径
206 showDebugInfo("分支路径栈弹出:" + pInfo.startNode + "-->"
207 + pInfo.endNode, depth);
208 // 为了防止头尾一样的路径,有了下面的判断,理论上是没有,但实际会出现
209 if (pInfo.startNode == pInfo.endNode)
210 {
211 showDebugInfo("头尾节点一样,丢弃!", depth + 1);
212 continue;
213 }
214
215 // 如果存在可到达的路径的话,注意,这是个递归过程
216 if (pInfo.startNode == sNode)
217 {
218 // 当前路径加入回退栈,此时,回退栈里可以找出一条完整的路径了
219 backTrackStack.push(pInfo);
220 showDebugInfo("--------到达起点:" + pInfo.startNode + "-->"
221 + pInfo.endNode + "--------", depth);
222 int numbackTrackStack = backTrackStack.size();
223 resultTemp = new Stack();
224 lastingTime = 0;
225 for (int j = 0; j < numbackTrackStack; j++)
226 {
227 pInfo = (ProcessInfo) backTrackStack.get(j);
228 showDebugInfo("回溯栈内容进入临时结果栈:" + pInfo.startNode + "-->"
229 + pInfo.endNode, depth);
230 lastingTime += pInfo.lastingTime;
231 resultTemp.push(pInfo);
232 }
233 // 判断是不是更好的解
234 if (lastingTime > maxLastingTime)
235 {
236 showDebugInfo("========找到更优解!========", depth);
237 maxLastingTime = lastingTime;
238 resultStack = resultTemp;
239 }
240 // 找出一条后,需要回退,然后继续找下一条
241 // 获得剩余分支路径的数目
242 int numBranch = branchProcessStack.size();
243
244 if (numBranch == 0)
245 {
246 // 没分支路径了,查找结束,清空回退栈
247 backTrackStack.removeAllElements();
248 }
249 else if (numBranch > 0)
250 {
251 int index = numBranch - 1;
252 int backTrackValue = ((ProcessInfo) branchProcessStack
253 .get(index)).endNode;
254 showDebugInfo("--------回退到节点:" + backTrackValue
255 + "--------", depth);
256 // 要回退到的节点必是分支路径栈中最上路径的尾节点
257 // 下面的循环就是一直回退,由于还有分支路径,所以可以找到要退到的点
258 do
259 {
260 pInfo = (ProcessInfo) backTrackStack.pop();
261 showDebugInfo("找到目标,回溯栈回退到:" + pInfo.startNode
262 + "-->" + pInfo.endNode, depth);
263 }
264 while (pInfo.endNode != backTrackValue);
265 }
266 // 回退后,继续查找的话,所有路径的经过标记都要重置,否则经过了的路径是不会再去查的
267 // 由于开始路径不同,所以不会找到同样的结果
268 resetAllSkip();
269 continue;// 开始从下个分支路径查找
270 }
271 else
272 // 没有直接从sNode到eNode的工序
273 {
274 // 还没到目标
275 // 如果当前路径的起点还有前驱节点的话,需要递归查找,这是重点
276 if (pInfo.hasFrontNode)
277 {
278 ProcessInfo btPInfo = new ProcessInfo(sNode, eNode,
279 pInfo.lastingTime);
280 btPInfo.eNodeIsBranchEndNode = pInfo.eNodeIsBranchEndNode;
281 // 说明找过sNode-->eNode
282 backTrackStack.push(btPInfo);
283 showDebugInfo("回溯栈加入:" + sNode + "-->" + eNode
284 + ",说明找过" + sNode + "-->" + eNode, depth + 1);
285 showDebugInfo("查找:" + sNode + "-->" + pInfo.startNode,
286 depth + 1);
287 searchProcess(sNode, pInfo.startNode, depth + 2);
288 }
289 else
290 // 当前路径的起点无前驱,则路径错误,需要回溯
291 {
292 // 如果当前路径的终结点还有其它前驱的话,则退出本次循环,从下个分支路径查找
293 if (pInfo.eNodeIsBranchEndNode)
294 {
295 continue;
296 }
297 // 如果当前路径的终结点没有其它前驱,就要回退了
298 else if (backTrackStack.size() > 0)
299 {
300 // 开始回退,一直到找到个路径的终止节点有多个前驱为止,或者是回退栈已经空了。
301 do
302 {
303 pInfo = (ProcessInfo) backTrackStack.pop();
304 showDebugInfo("路径错误,开始回溯,回溯栈弹出:"
305 + pInfo.startNode + "-->"
306 + pInfo.endNode, depth + 1);
307 }
308 while ((!pInfo.eNodeIsBranchEndNode)
309 && (backTrackStack.size() > 0));
310 }
311 }
312 }
313 }
314 showDebugInfo("分支已被找遍", depth);
315 }
316 else
317 {
318 showDebugInfo("前面已走过这条路径且被证明走不通,或尾节点没有前驱节点", depth);
319 if (backTrackStack.size()>0)
320 {
321 pInfo = (ProcessInfo) backTrackStack.pop();
322 showDebugInfo("路径不通,回溯栈弹出:" + pInfo.startNode + "-->"
323 + pInfo.endNode, depth - 1);
324 if (branchProcessStack.size()>0)
325 {
326 int fixNode = ((ProcessInfo) branchProcessStack.lastElement()).endNode;
327 if (fixNode != pInfo.endNode)
328 {
329 showDebugInfo("========需要调整回溯栈========", depth);
330 showDebugInfo("========开始调整回溯栈========", depth);
331 do
332 {
333 pInfo = (ProcessInfo) backTrackStack.pop();
334 showDebugInfo("回溯栈弹出:" + pInfo.startNode + "-->"
335 + pInfo.endNode, depth + 1);
336 }
337 while (fixNode != pInfo.endNode);
338 showDebugInfo("========回溯栈调整结束========", depth);
339 }
340 }
341 }
342 }
343 }
344
345 private void showDebugInfo(String info, int blankCount)
346 {
347 String blank = "";
348 for (int i = 0; i < blankCount; i++)
349 {
350 blank += " ";
351 }
352 System.out.println(blank + info);
353 }
354
355 public int getLastingTime(int sNode, int eNode)
356 {
357 int lastingTime = 0;
358 ProcessInfo pInfo;
359 searchProcess(sNode, eNode, 0);
360 int num = resultStack.size();
361 for (int i = num - 1; i >= 0; i--)
362 {
363 pInfo = (ProcessInfo) resultStack.get(i);
364 lastingTime += pInfo.lastingTime;
365 }
366 return lastingTime;
367 }
368
369 public void showPath()
370 {
371 ProcessInfo pInfo;
372 int num = resultStack.size();
373 if (num==0)
374 {
375 showDebugInfo("========没有符合要求的路径========",0);
376 }
377 else
378 {
379 for (int i = 0; i < num; i++)
380 {
381 pInfo = (ProcessInfo) resultStack.pop();
382 System.out.print("-->" + pInfo.endNode);
383 }
384 }
385 }
386
387 public void resetAllSkip()
388 {
389 for (int i = 0; i < numProcess; i++)
390 {
391 process[i].skip = false;
392 }
393 }
394
395 public int getItemEarliestBeginTime(int itemIndex)
396 {
397 maxLastingTime = 0;
398 backTrackStack.removeAllElements();
399 resultStack.removeAllElements();
400 return getLastingTime(1, itemIndex);
401 }
402
403 public int getProcessEarliestEndTime(int sNode, int eNode)
404 {
405 for (int i = 0; i < numProcess; i++)
406 {
407 if ((process[i].startNode == sNode)
408 && (process[i].endNode == eNode))
409 {
410 return (getItemEarliestBeginTime(sNode) + process[i].lastingTime);
411 }
412 }
413 return 0;
414 }
415
416 public int getProcessEarliestBeginTime(int sNode, int eNode)
417 {
418 return (getItemEarliestBeginTime(sNode));
419 }
420
421 public int getItemLatestEndTime(int itemIndex)
422 {
423 int maxTime = 0;
424 int t = 0;
425 int pos = -1;
426 boolean hasNextNode = false;
427 backTrackStack.removeAllElements();
428 resultStack.removeAllElements();
429 for (int i = 0; i < numProcess; i++)
430 {
431 if (process[i].startNode == itemIndex)
432 {
433 if (process[i].sNodeIsBranchBeginNode)
434 {
435 return (getItemEarliestBeginTime(itemIndex));
436 }
437 hasNextNode = true;
438 t = getItemEarliestBeginTime(process[i].endNode);
439 if (t > maxTime)
440 {
441 pos = i;
442 maxTime = t;
443 }
444 }
445 }
446 if (!hasNextNode)
447 {
448 return (getItemEarliestBeginTime(itemIndex));
449 }
450 else
451 {
452 return (t - process[pos].lastingTime);
453 }
454 }
455
456 public int getProcessLatestEndTime(int sNode, int eNode)
457 {
458 return (getItemLatestEndTime(eNode));
459 }
460
461 public int getProcessLatestBeginTime(int sNode, int eNode)
462 {
463 for (int i = 0; i < numProcess; i++)
464 {
465 if ((process[i].startNode == sNode)
466 && (process[i].endNode == eNode))
467 {
468 return (getProcessLatestEndTime(sNode, eNode) - process[i].lastingTime);
469 }
470 }
471 return 0;
472 }
473
474 public int getProcessIntervalTime(int sNode, int eNode)
475 {
476 return (getProcessLatestEndTime(sNode, eNode) - getProcessEarliestEndTime(
477 sNode, eNode));
478 }
479
480 public int getKeyPath(int sNode, int eNode)
481 {
482 if ((getProcessIntervalTime(sNode, eNode) == 0) && (sNode != eNode))
483 {
484 return eNode;
485 }
486 else
487 {
488 return 0;
489 }
490 }
491}
分支路径栈加入:7-->8
分支路径栈加入:8-->8
分支路径栈弹出:8-->8
头尾节点一样,丢弃!
分支路径栈弹出:7-->8
回溯栈加入:2-->8,说明找过2-->8
查找:2-->7
分支路径栈加入:2-->7
分支路径栈加入:3-->7
分支路径栈加入:5-->7
分支路径栈加入:6-->7
分支路径栈弹出:6-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->6
分支路径栈加入:4-->6
分支路径栈弹出:4-->6
回溯栈加入:2-->6,说明找过2-->6
查找:2-->4
分支路径栈加入:2-->4
分支路径栈弹出:2-->4
--------到达起点:2-->4--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->6
回溯栈内容进入临时结果栈:2-->4
========找到更优解!========
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->4
找到目标,回溯栈回退到:2-->6
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支已被找遍
分支路径栈弹出:5-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->5
分支路径栈加入:2-->5
分支路径栈加入:4-->5
分支路径栈弹出:4-->5
回溯栈加入:2-->5,说明找过2-->5
查找:2-->4
分支路径栈加入:2-->4
分支路径栈弹出:2-->4
--------到达起点:2-->4--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->5
回溯栈内容进入临时结果栈:2-->4
--------回退到节点:5--------
找到目标,回溯栈回退到:2-->4
找到目标,回溯栈回退到:2-->5
分支已被找遍
分支路径栈弹出:2-->5
--------到达起点:2-->5--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->5
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->5
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支路径栈弹出:3-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->3
分支路径栈加入:2-->3
分支路径栈弹出:2-->3
--------到达起点:2-->3--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->3
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->3
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支路径栈弹出:2-->7
--------到达起点:2-->7--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
分支已被找遍
分支已被找遍
-->4-->6-->7-->8
下面来个找3到7的:分支路径栈加入:8-->8
分支路径栈弹出:8-->8
头尾节点一样,丢弃!
分支路径栈弹出:7-->8
回溯栈加入:2-->8,说明找过2-->8
查找:2-->7
分支路径栈加入:2-->7
分支路径栈加入:3-->7
分支路径栈加入:5-->7
分支路径栈加入:6-->7
分支路径栈弹出:6-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->6
分支路径栈加入:4-->6
分支路径栈弹出:4-->6
回溯栈加入:2-->6,说明找过2-->6
查找:2-->4
分支路径栈加入:2-->4
分支路径栈弹出:2-->4
--------到达起点:2-->4--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->6
回溯栈内容进入临时结果栈:2-->4
========找到更优解!========
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->4
找到目标,回溯栈回退到:2-->6
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支已被找遍
分支路径栈弹出:5-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->5
分支路径栈加入:2-->5
分支路径栈加入:4-->5
分支路径栈弹出:4-->5
回溯栈加入:2-->5,说明找过2-->5
查找:2-->4
分支路径栈加入:2-->4
分支路径栈弹出:2-->4
--------到达起点:2-->4--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->5
回溯栈内容进入临时结果栈:2-->4
--------回退到节点:5--------
找到目标,回溯栈回退到:2-->4
找到目标,回溯栈回退到:2-->5
分支已被找遍
分支路径栈弹出:2-->5
--------到达起点:2-->5--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->5
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->5
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支路径栈弹出:3-->7
回溯栈加入:2-->7,说明找过2-->7
查找:2-->3
分支路径栈加入:2-->3
分支路径栈弹出:2-->3
--------到达起点:2-->3--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
回溯栈内容进入临时结果栈:2-->3
--------回退到节点:7--------
找到目标,回溯栈回退到:2-->3
找到目标,回溯栈回退到:2-->7
分支已被找遍
分支路径栈弹出:2-->7
--------到达起点:2-->7--------
回溯栈内容进入临时结果栈:2-->8
回溯栈内容进入临时结果栈:2-->7
分支已被找遍
分支已被找遍
-->4-->6-->7-->8
1分支路径栈加入:2-->7
2分支路径栈加入:3-->7
3分支路径栈加入:5-->7
4分支路径栈加入:6-->7
5分支路径栈弹出:6-->7
6 回溯栈加入:3-->7,说明找过3-->7
7 查找:3-->6
8 分支路径栈加入:4-->6
9 分支路径栈弹出:4-->6
10 回溯栈加入:3-->6,说明找过3-->6
11 查找:3-->4
12 分支路径栈加入:2-->4
13 分支路径栈弹出:2-->4
14 回溯栈加入:3-->4,说明找过3-->4
15 查找:3-->2
16 分支路径栈加入:1-->2
17 分支路径栈弹出:1-->2
18 路径错误,开始回溯,回溯栈弹出:3-->4
19 路径错误,开始回溯,回溯栈弹出:3-->6
20 路径错误,开始回溯,回溯栈弹出:3-->7
21 分支已被找遍
22 分支已被找遍
23 分支已被找遍
24分支路径栈弹出:5-->7
25 回溯栈加入:3-->7,说明找过3-->7
26 查找:3-->5
27 分支路径栈加入:2-->5
28 分支路径栈加入:4-->5
29 分支路径栈弹出:4-->5
30 回溯栈加入:3-->5,说明找过3-->5
31 查找:3-->4
32 前面已走过这条路径且被证明走不通,或尾节点没有前驱节点
33 路径不通,回溯栈弹出:3-->5
34 分支路径栈弹出:2-->5
35 回溯栈加入:3-->5,说明找过3-->5
36 查找:3-->2
37 前面已走过这条路径且被证明走不通,或尾节点没有前驱节点
38 路径不通,回溯栈弹出:3-->5
39 ========需要调整回溯栈========
40 ========开始调整回溯栈========
41 回溯栈弹出:3-->7
42 ========回溯栈调整结束========
43 分支已被找遍
44分支路径栈弹出:3-->7
45--------到达起点:3-->7--------
46回溯栈内容进入临时结果栈:3-->7
47========找到更优解!========
48--------回退到节点:7--------
49找到目标,回溯栈回退到:3-->7
50分支路径栈弹出:2-->7
51 回溯栈加入:3-->7,说明找过3-->7
52 查找:3-->2
53 分支路径栈加入:1-->2
54 分支路径栈弹出:1-->2
55 路径错误,开始回溯,回溯栈弹出:3-->7
56 分支已被找遍
57分支已被找遍
58-->7
先写到这里,以后再来修改。
2分支路径栈加入:3-->7
3分支路径栈加入:5-->7
4分支路径栈加入:6-->7
5分支路径栈弹出:6-->7
6 回溯栈加入:3-->7,说明找过3-->7
7 查找:3-->6
8 分支路径栈加入:4-->6
9 分支路径栈弹出:4-->6
10 回溯栈加入:3-->6,说明找过3-->6
11 查找:3-->4
12 分支路径栈加入:2-->4
13 分支路径栈弹出:2-->4
14 回溯栈加入:3-->4,说明找过3-->4
15 查找:3-->2
16 分支路径栈加入:1-->2
17 分支路径栈弹出:1-->2
18 路径错误,开始回溯,回溯栈弹出:3-->4
19 路径错误,开始回溯,回溯栈弹出:3-->6
20 路径错误,开始回溯,回溯栈弹出:3-->7
21 分支已被找遍
22 分支已被找遍
23 分支已被找遍
24分支路径栈弹出:5-->7
25 回溯栈加入:3-->7,说明找过3-->7
26 查找:3-->5
27 分支路径栈加入:2-->5
28 分支路径栈加入:4-->5
29 分支路径栈弹出:4-->5
30 回溯栈加入:3-->5,说明找过3-->5
31 查找:3-->4
32 前面已走过这条路径且被证明走不通,或尾节点没有前驱节点
33 路径不通,回溯栈弹出:3-->5
34 分支路径栈弹出:2-->5
35 回溯栈加入:3-->5,说明找过3-->5
36 查找:3-->2
37 前面已走过这条路径且被证明走不通,或尾节点没有前驱节点
38 路径不通,回溯栈弹出:3-->5
39 ========需要调整回溯栈========
40 ========开始调整回溯栈========
41 回溯栈弹出:3-->7
42 ========回溯栈调整结束========
43 分支已被找遍
44分支路径栈弹出:3-->7
45--------到达起点:3-->7--------
46回溯栈内容进入临时结果栈:3-->7
47========找到更优解!========
48--------回退到节点:7--------
49找到目标,回溯栈回退到:3-->7
50分支路径栈弹出:2-->7
51 回溯栈加入:3-->7,说明找过3-->7
52 查找:3-->2
53 分支路径栈加入:1-->2
54 分支路径栈弹出:1-->2
55 路径错误,开始回溯,回溯栈弹出:3-->7
56 分支已被找遍
57分支已被找遍
58-->7