打印0—N(0<=N<=9)的所有路径。
想起以前那个工序最优解的解法,好像差不多,改一改,就ok了。
import java.util.Stack;
/**
* @author zxub Created on 2005-5-22 10:19:51
*/
public class ProcessOpera
{
final int MAX = 20;
// 保存路径信息的数组
ProcessInfo process[] = new ProcessInfo[MAX];
// 保存路径数目
int numProcess = 0;
// 分支路径栈
Stack branchProcessStack = new Stack();
// 用于搜索回退的栈
Stack backTrackStack = new Stack();
// 保存最后结果的栈
Stack resultStack = new Stack();
// 最长持续时间
int maxLastingTime = 0;
private int sNode;
/**
* 初始化所有路径信息,放进数组中
*/
public void setup()
{
addProcessInfo(0, 1);
addProcessInfo(0, 2);
addProcessInfo(1, 2);
addProcessInfo(1, 3);
addProcessInfo(2, 3);
addProcessInfo(2, 4);
addProcessInfo(3, 4);
addProcessInfo(3, 5);
addProcessInfo(4, 5);
addProcessInfo(4, 6);
addProcessInfo(5, 6);
addProcessInfo(5, 7);
addProcessInfo(6, 7);
addProcessInfo(6, 8);
addProcessInfo(7, 8);
addProcessInfo(7, 9);
addProcessInfo(8, 9);
}
/**
* 增加路径信息到数组中
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param lTime
* 持续时间
*/
public void addProcessInfo(int sNode, int eNode)
{
if (numProcess < MAX) // 如果数组没满的话
{
process[numProcess] = new ProcessInfo(sNode, eNode);
numProcess++;
}
else
{
System.out
.println("ProcessInfo database full!\nAdd error,program exit!");
System.exit(0);
}
}
/**
* 给所有路径信息中的附加属性赋值,要完成的话,需要遍历路径数组中的所有元素。 对于每个元素,要查看数组中的其它元素,确立关系
*/
public void setNodeTag()
{
for (int i = 0; i < numProcess; i++) // 遍历路径数组中的所有元素,process[i]是选取的路径
{
for (int j = 0; j < numProcess; j++) // 查看其它元素
{
if (i == j) continue; // 自己比自己,没得比,继续下次循环
// 发现有路径可以和选取路径连接
if (process[j].endNode == process[i].startNode)
{
process[i].hasFrontNode = true;
}
// 两条不同路径的终结点一样
if (process[j].endNode == process[i].endNode)
{
process[i].eNodeIsBranchEndNode = true;
}
// 两条不同路径的起始点一样
if (process[j].startNode == process[i].startNode)
{
process[i].sNodeIsBranchBeginNode = true;
}
}
}
}
/**
* 找出以选取点为终结点的没走过的一条路径
*
* @param eNode
* 所选取的点
* @return 没被走过的以选取点为终结点的一条路径
*/
public ProcessInfo findProcessInfo(int eNode)
{
for (int i = 0; i < numProcess; i++) // 遍历路径信息
{
// process[i].skip=false 路径才没被走过
if ((process[i].endNode == eNode) && (!process[i].skip))
{
// 由于深度复制和浅度复制的问题,所以复制的时候要新建一个ProcessInfo,而不是引用原来
// 这是实现问题,算法与此可以无关
ProcessInfo pInfo = new ProcessInfo(process[i].startNode,
process[i].endNode);
process[i].skip = true;
pInfo.hasFrontNode = process[i].hasFrontNode;
pInfo.eNodeIsBranchEndNode = process[i].eNodeIsBranchEndNode;
return pInfo;
}
}
return null; // 没有合适的路径就返回null了
}
/**
* 核心部分所在,查找任意2点间最长路径 基于AI设计,简单的AI 理论上来说,顺着找和倒着找是一样的,由于项目原因,这里我是倒着找的
* 查找到的路径放在结果栈resultStack中
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param depth
* 显示debug信息的时候用到,用于显示层次关系
*/
public void searchProcess(int sNode, int eNode, int depth)
{
this.sNode=sNode;
ProcessInfo pInfo; // 保存路径信息的对象
int numStartNode = 0; // 查找起点的个数
Stack resultTemp; // 保存查找到路径的临时栈
while ((pInfo = findProcessInfo(eNode)) != null)
{
// 分支节点数目+1
numStartNode++;
// 将查找到的路径信息放到分支节点栈,然后再查
branchProcessStack.push(pInfo);
showDebugInfo("分支路径栈加入:" + pInfo.startNode + "-->" + pInfo.endNode,
depth);
}
if (numStartNode > 0) // 有分支的话,如果这里不成立,整个就结束了
{
for (int i = 0; i < numStartNode; i++) // 遍历分支节点栈
{
pInfo = (ProcessInfo) branchProcessStack.pop(); // 获得一条分支路径
showDebugInfo("分支路径栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth);
// 为了防止头尾一样的路径,有了下面的判断,理论上是没有,但实际会出现
if (pInfo.startNode == pInfo.endNode)
{
showDebugInfo("头尾节点一样,丢弃!", depth + 1);
continue;
}
// 如果存在可到达的路径的话,注意,这是个递归过程
if (pInfo.startNode == sNode)
{
// 当前路径加入回退栈,此时,回退栈里可以找出一条完整的路径了
backTrackStack.push(pInfo);
showDebugInfo("--------到达起点:" + pInfo.startNode + "-->"
+ pInfo.endNode + "--------", depth);
int numbackTrackStack = backTrackStack.size();
resultTemp = new Stack();
for (int j = 0; j < numbackTrackStack; j++)
{
pInfo = (ProcessInfo) backTrackStack.get(j);
showDebugInfo("回溯栈内容进入临时结果栈:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth);
resultTemp.push(pInfo);
}
resultStack = resultTemp;
showPath();
// 找出一条后,需要回退,然后继续找下一条
// 获得剩余分支路径的数目
int numBranch = branchProcessStack.size();
if (numBranch == 0)
{
// 没分支路径了,查找结束,清空回退栈
backTrackStack.removeAllElements();
}
else if (numBranch > 0)
{
int index = numBranch - 1;
int backTrackValue = ((ProcessInfo) branchProcessStack
.get(index)).endNode;
showDebugInfo("--------回退到节点:" + backTrackValue
+ "--------", depth);
// 要回退到的节点必是分支路径栈中最上路径的尾节点
// 下面的循环就是一直回退,由于还有分支路径,所以可以找到要退到的点
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("找到目标,回溯栈回退到:" + pInfo.startNode
+ "-->" + pInfo.endNode, depth);
}
while (pInfo.endNode != backTrackValue);
}
// 回退后,继续查找的话,所有路径的经过标记都要重置,否则经过了的路径是不会再去查的
// 由于开始路径不同,所以不会找到同样的结果
resetAllSkip();
continue;// 开始从下个分支路径查找
}
else
// 没有直接从sNode到eNode的工序
{
// 还没到目标
// 如果当前路径的起点还有前驱节点的话,需要递归查找,这是重点
if (pInfo.hasFrontNode)
{
ProcessInfo btPInfo = new ProcessInfo(sNode, eNode);
btPInfo.eNodeIsBranchEndNode = pInfo.eNodeIsBranchEndNode;
// 说明找过sNode-->eNode
backTrackStack.push(btPInfo);
showDebugInfo("回溯栈加入:" + sNode + "-->" + eNode
+ ",说明找过" + sNode + "-->" + eNode, depth + 1);
showDebugInfo("查找:" + sNode + "-->" + pInfo.startNode,
depth + 1);
searchProcess(sNode, pInfo.startNode, depth + 2);
}
else
// 当前路径的起点无前驱,则路径错误,需要回溯
{
// 如果当前路径的终结点还有其它前驱的话,则退出本次循环,从下个分支路径查找
if (pInfo.eNodeIsBranchEndNode)
{
continue;
}
// 如果当前路径的终结点没有其它前驱,就要回退了
else if (backTrackStack.size() > 0)
{
// 开始回退,一直到找到个路径的终止节点有多个前驱为止,或者是回退栈已经空了。
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("路径错误,开始回溯,回溯栈弹出:"
+ pInfo.startNode + "-->"
+ pInfo.endNode, depth + 1);
}
while ((!pInfo.eNodeIsBranchEndNode)
&& (backTrackStack.size() > 0));
}
}
}
}
showDebugInfo("分支已被找遍", depth);
}
else
{
showDebugInfo("前面已走过这条路径且被证明走不通,或尾节点没有前驱节点", depth);
if (backTrackStack.size() > 0)
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("路径不通,回溯栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth - 1);
if (branchProcessStack.size() > 0)
{
int fixNode = ((ProcessInfo) branchProcessStack
.lastElement()).endNode;
if (fixNode != pInfo.endNode)
{
showDebugInfo("========需要调整回溯栈========", depth);
showDebugInfo("========开始调整回溯栈========", depth);
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("回溯栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth + 1);
}
while (fixNode != pInfo.endNode);
showDebugInfo("========回溯栈调整结束========", depth);
}
}
}
}
}
private void showDebugInfo(String info, int blankCount)
{
// String blank = "";
// for (int i = 0; i < blankCount; i++)
// {
// blank += " ";
// }
// System.out.println(blank + info);
}
public void showPath()
{
ProcessInfo pInfo;
int num = resultStack.size();
if (num == 0)
{
// showDebugInfo("========没有符合要求的路径========", 0);
}
else
{
System.out.print(this.sNode);
for (int i = 0; i < num; i++)
{
pInfo = (ProcessInfo) resultStack.pop();
System.out.print("-->" + pInfo.endNode);
}
System.out.println();
}
}
public void resetAllSkip()
{
for (int i = 0; i < numProcess; i++)
{
process[i].skip = false;
}
}
public static void main(String[] args)
{
ProcessOpera processOpera = new ProcessOpera();
processOpera.setup();
processOpera.setNodeTag();
for (int i = 0; i <= 9; i++)
{
processOpera.resetAllSkip();
processOpera.searchProcess(0, i, 0);
}
//processOpera.searchProcess(0, 4, 0);
}
public class ProcessInfo
{
// 基本信息:startNode,endNode
protected int startNode; // 开始节点
protected int endNode; // 终止节点
protected int lastingTime; // 路径持续时间
// 下面是附加信息,遍历的时候用到
protected boolean skip; // 判断该路径是否已经走过
protected boolean hasFrontNode; // 路径是否有前驱节点
protected boolean eNodeIsBranchEndNode; // 路径终止节点是否有多个前驱
protected boolean sNodeIsBranchBeginNode; // 路径开始节点是否有多个后继
/**
* 保存任意两点间路径信息
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param lTime
* 持续时间
*/
public ProcessInfo(int sNode, int eNode)
{
this.startNode = sNode;
this.endNode = eNode;
// 由于是刚开始保存,下面的几个信息不能确立,所以都是false
this.skip = false;
this.hasFrontNode = false;
this.eNodeIsBranchEndNode = false;
this.sNodeIsBranchBeginNode = false;
}
}
}
答案如下:/**
* @author zxub Created on 2005-5-22 10:19:51
*/
public class ProcessOpera
{
final int MAX = 20;
// 保存路径信息的数组
ProcessInfo process[] = new ProcessInfo[MAX];
// 保存路径数目
int numProcess = 0;
// 分支路径栈
Stack branchProcessStack = new Stack();
// 用于搜索回退的栈
Stack backTrackStack = new Stack();
// 保存最后结果的栈
Stack resultStack = new Stack();
// 最长持续时间
int maxLastingTime = 0;
private int sNode;
/**
* 初始化所有路径信息,放进数组中
*/
public void setup()
{
addProcessInfo(0, 1);
addProcessInfo(0, 2);
addProcessInfo(1, 2);
addProcessInfo(1, 3);
addProcessInfo(2, 3);
addProcessInfo(2, 4);
addProcessInfo(3, 4);
addProcessInfo(3, 5);
addProcessInfo(4, 5);
addProcessInfo(4, 6);
addProcessInfo(5, 6);
addProcessInfo(5, 7);
addProcessInfo(6, 7);
addProcessInfo(6, 8);
addProcessInfo(7, 8);
addProcessInfo(7, 9);
addProcessInfo(8, 9);
}
/**
* 增加路径信息到数组中
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param lTime
* 持续时间
*/
public void addProcessInfo(int sNode, int eNode)
{
if (numProcess < MAX) // 如果数组没满的话
{
process[numProcess] = new ProcessInfo(sNode, eNode);
numProcess++;
}
else
{
System.out
.println("ProcessInfo database full!\nAdd error,program exit!");
System.exit(0);
}
}
/**
* 给所有路径信息中的附加属性赋值,要完成的话,需要遍历路径数组中的所有元素。 对于每个元素,要查看数组中的其它元素,确立关系
*/
public void setNodeTag()
{
for (int i = 0; i < numProcess; i++) // 遍历路径数组中的所有元素,process[i]是选取的路径
{
for (int j = 0; j < numProcess; j++) // 查看其它元素
{
if (i == j) continue; // 自己比自己,没得比,继续下次循环
// 发现有路径可以和选取路径连接
if (process[j].endNode == process[i].startNode)
{
process[i].hasFrontNode = true;
}
// 两条不同路径的终结点一样
if (process[j].endNode == process[i].endNode)
{
process[i].eNodeIsBranchEndNode = true;
}
// 两条不同路径的起始点一样
if (process[j].startNode == process[i].startNode)
{
process[i].sNodeIsBranchBeginNode = true;
}
}
}
}
/**
* 找出以选取点为终结点的没走过的一条路径
*
* @param eNode
* 所选取的点
* @return 没被走过的以选取点为终结点的一条路径
*/
public ProcessInfo findProcessInfo(int eNode)
{
for (int i = 0; i < numProcess; i++) // 遍历路径信息
{
// process[i].skip=false 路径才没被走过
if ((process[i].endNode == eNode) && (!process[i].skip))
{
// 由于深度复制和浅度复制的问题,所以复制的时候要新建一个ProcessInfo,而不是引用原来
// 这是实现问题,算法与此可以无关
ProcessInfo pInfo = new ProcessInfo(process[i].startNode,
process[i].endNode);
process[i].skip = true;
pInfo.hasFrontNode = process[i].hasFrontNode;
pInfo.eNodeIsBranchEndNode = process[i].eNodeIsBranchEndNode;
return pInfo;
}
}
return null; // 没有合适的路径就返回null了
}
/**
* 核心部分所在,查找任意2点间最长路径 基于AI设计,简单的AI 理论上来说,顺着找和倒着找是一样的,由于项目原因,这里我是倒着找的
* 查找到的路径放在结果栈resultStack中
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param depth
* 显示debug信息的时候用到,用于显示层次关系
*/
public void searchProcess(int sNode, int eNode, int depth)
{
this.sNode=sNode;
ProcessInfo pInfo; // 保存路径信息的对象
int numStartNode = 0; // 查找起点的个数
Stack resultTemp; // 保存查找到路径的临时栈
while ((pInfo = findProcessInfo(eNode)) != null)
{
// 分支节点数目+1
numStartNode++;
// 将查找到的路径信息放到分支节点栈,然后再查
branchProcessStack.push(pInfo);
showDebugInfo("分支路径栈加入:" + pInfo.startNode + "-->" + pInfo.endNode,
depth);
}
if (numStartNode > 0) // 有分支的话,如果这里不成立,整个就结束了
{
for (int i = 0; i < numStartNode; i++) // 遍历分支节点栈
{
pInfo = (ProcessInfo) branchProcessStack.pop(); // 获得一条分支路径
showDebugInfo("分支路径栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth);
// 为了防止头尾一样的路径,有了下面的判断,理论上是没有,但实际会出现
if (pInfo.startNode == pInfo.endNode)
{
showDebugInfo("头尾节点一样,丢弃!", depth + 1);
continue;
}
// 如果存在可到达的路径的话,注意,这是个递归过程
if (pInfo.startNode == sNode)
{
// 当前路径加入回退栈,此时,回退栈里可以找出一条完整的路径了
backTrackStack.push(pInfo);
showDebugInfo("--------到达起点:" + pInfo.startNode + "-->"
+ pInfo.endNode + "--------", depth);
int numbackTrackStack = backTrackStack.size();
resultTemp = new Stack();
for (int j = 0; j < numbackTrackStack; j++)
{
pInfo = (ProcessInfo) backTrackStack.get(j);
showDebugInfo("回溯栈内容进入临时结果栈:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth);
resultTemp.push(pInfo);
}
resultStack = resultTemp;
showPath();
// 找出一条后,需要回退,然后继续找下一条
// 获得剩余分支路径的数目
int numBranch = branchProcessStack.size();
if (numBranch == 0)
{
// 没分支路径了,查找结束,清空回退栈
backTrackStack.removeAllElements();
}
else if (numBranch > 0)
{
int index = numBranch - 1;
int backTrackValue = ((ProcessInfo) branchProcessStack
.get(index)).endNode;
showDebugInfo("--------回退到节点:" + backTrackValue
+ "--------", depth);
// 要回退到的节点必是分支路径栈中最上路径的尾节点
// 下面的循环就是一直回退,由于还有分支路径,所以可以找到要退到的点
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("找到目标,回溯栈回退到:" + pInfo.startNode
+ "-->" + pInfo.endNode, depth);
}
while (pInfo.endNode != backTrackValue);
}
// 回退后,继续查找的话,所有路径的经过标记都要重置,否则经过了的路径是不会再去查的
// 由于开始路径不同,所以不会找到同样的结果
resetAllSkip();
continue;// 开始从下个分支路径查找
}
else
// 没有直接从sNode到eNode的工序
{
// 还没到目标
// 如果当前路径的起点还有前驱节点的话,需要递归查找,这是重点
if (pInfo.hasFrontNode)
{
ProcessInfo btPInfo = new ProcessInfo(sNode, eNode);
btPInfo.eNodeIsBranchEndNode = pInfo.eNodeIsBranchEndNode;
// 说明找过sNode-->eNode
backTrackStack.push(btPInfo);
showDebugInfo("回溯栈加入:" + sNode + "-->" + eNode
+ ",说明找过" + sNode + "-->" + eNode, depth + 1);
showDebugInfo("查找:" + sNode + "-->" + pInfo.startNode,
depth + 1);
searchProcess(sNode, pInfo.startNode, depth + 2);
}
else
// 当前路径的起点无前驱,则路径错误,需要回溯
{
// 如果当前路径的终结点还有其它前驱的话,则退出本次循环,从下个分支路径查找
if (pInfo.eNodeIsBranchEndNode)
{
continue;
}
// 如果当前路径的终结点没有其它前驱,就要回退了
else if (backTrackStack.size() > 0)
{
// 开始回退,一直到找到个路径的终止节点有多个前驱为止,或者是回退栈已经空了。
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("路径错误,开始回溯,回溯栈弹出:"
+ pInfo.startNode + "-->"
+ pInfo.endNode, depth + 1);
}
while ((!pInfo.eNodeIsBranchEndNode)
&& (backTrackStack.size() > 0));
}
}
}
}
showDebugInfo("分支已被找遍", depth);
}
else
{
showDebugInfo("前面已走过这条路径且被证明走不通,或尾节点没有前驱节点", depth);
if (backTrackStack.size() > 0)
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("路径不通,回溯栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth - 1);
if (branchProcessStack.size() > 0)
{
int fixNode = ((ProcessInfo) branchProcessStack
.lastElement()).endNode;
if (fixNode != pInfo.endNode)
{
showDebugInfo("========需要调整回溯栈========", depth);
showDebugInfo("========开始调整回溯栈========", depth);
do
{
pInfo = (ProcessInfo) backTrackStack.pop();
showDebugInfo("回溯栈弹出:" + pInfo.startNode + "-->"
+ pInfo.endNode, depth + 1);
}
while (fixNode != pInfo.endNode);
showDebugInfo("========回溯栈调整结束========", depth);
}
}
}
}
}
private void showDebugInfo(String info, int blankCount)
{
// String blank = "";
// for (int i = 0; i < blankCount; i++)
// {
// blank += " ";
// }
// System.out.println(blank + info);
}
public void showPath()
{
ProcessInfo pInfo;
int num = resultStack.size();
if (num == 0)
{
// showDebugInfo("========没有符合要求的路径========", 0);
}
else
{
System.out.print(this.sNode);
for (int i = 0; i < num; i++)
{
pInfo = (ProcessInfo) resultStack.pop();
System.out.print("-->" + pInfo.endNode);
}
System.out.println();
}
}
public void resetAllSkip()
{
for (int i = 0; i < numProcess; i++)
{
process[i].skip = false;
}
}
public static void main(String[] args)
{
ProcessOpera processOpera = new ProcessOpera();
processOpera.setup();
processOpera.setNodeTag();
for (int i = 0; i <= 9; i++)
{
processOpera.resetAllSkip();
processOpera.searchProcess(0, i, 0);
}
//processOpera.searchProcess(0, 4, 0);
}
public class ProcessInfo
{
// 基本信息:startNode,endNode
protected int startNode; // 开始节点
protected int endNode; // 终止节点
protected int lastingTime; // 路径持续时间
// 下面是附加信息,遍历的时候用到
protected boolean skip; // 判断该路径是否已经走过
protected boolean hasFrontNode; // 路径是否有前驱节点
protected boolean eNodeIsBranchEndNode; // 路径终止节点是否有多个前驱
protected boolean sNodeIsBranchBeginNode; // 路径开始节点是否有多个后继
/**
* 保存任意两点间路径信息
*
* @param sNode
* 开始节点
* @param eNode
* 终止节点
* @param lTime
* 持续时间
*/
public ProcessInfo(int sNode, int eNode)
{
this.startNode = sNode;
this.endNode = eNode;
// 由于是刚开始保存,下面的几个信息不能确立,所以都是false
this.skip = false;
this.hasFrontNode = false;
this.eNodeIsBranchEndNode = false;
this.sNodeIsBranchBeginNode = false;
}
}
}
0-->1
0-->1-->2
0-->2
0-->1-->2-->3
0-->2-->3
0-->1-->3
0-->1-->2-->3-->4
0-->2-->3-->4
0-->1-->3-->4
0-->1-->2-->4
0-->2-->4
0-->1-->2-->3-->4-->5
0-->2-->3-->4-->5
0-->1-->3-->4-->5
0-->1-->2-->4-->5
0-->2-->4-->5
0-->1-->2-->3-->5
0-->2-->3-->5
0-->1-->3-->5
0-->1-->2-->3-->4-->5-->6
0-->2-->3-->4-->5-->6
0-->1-->3-->4-->5-->6
0-->1-->2-->4-->5-->6
0-->2-->4-->5-->6
0-->1-->2-->3-->5-->6
0-->2-->3-->5-->6
0-->1-->3-->5-->6
0-->1-->2-->3-->4-->6
0-->2-->3-->4-->6
0-->1-->3-->4-->6
0-->1-->2-->4-->6
0-->2-->4-->6
0-->1-->2-->3-->4-->5-->6-->7
0-->2-->3-->4-->5-->6-->7
0-->1-->3-->4-->5-->6-->7
0-->1-->2-->4-->5-->6-->7
0-->2-->4-->5-->6-->7
0-->1-->2-->3-->5-->6-->7
0-->2-->3-->5-->6-->7
0-->1-->3-->5-->6-->7
0-->1-->2-->3-->4-->6-->7
0-->2-->3-->4-->6-->7
0-->1-->3-->4-->6-->7
0-->1-->2-->4-->6-->7
0-->2-->4-->6-->7
0-->1-->2-->3-->4-->5-->7
0-->2-->3-->4-->5-->7
0-->1-->3-->4-->5-->7
0-->1-->2-->4-->5-->7
0-->2-->4-->5-->7
0-->1-->2-->3-->5-->7
0-->2-->3-->5-->7
0-->1-->3-->5-->7
0-->1-->2-->3-->4-->5-->6-->7-->8
0-->2-->3-->4-->5-->6-->7-->8
0-->1-->3-->4-->5-->6-->7-->8
0-->1-->2-->4-->5-->6-->7-->8
0-->2-->4-->5-->6-->7-->8
0-->1-->2-->3-->5-->6-->7-->8
0-->2-->3-->5-->6-->7-->8
0-->1-->3-->5-->6-->7-->8
0-->1-->2-->3-->4-->6-->7-->8
0-->2-->3-->4-->6-->7-->8
0-->1-->3-->4-->6-->7-->8
0-->1-->2-->4-->6-->7-->8
0-->2-->4-->6-->7-->8
0-->1-->2-->3-->4-->5-->7-->8
0-->2-->3-->4-->5-->7-->8
0-->1-->3-->4-->5-->7-->8
0-->1-->2-->4-->5-->7-->8
0-->2-->4-->5-->7-->8
0-->1-->2-->3-->5-->7-->8
0-->2-->3-->5-->7-->8
0-->1-->3-->5-->7-->8
0-->1-->2-->3-->4-->5-->6-->8
0-->2-->3-->4-->5-->6-->8
0-->1-->3-->4-->5-->6-->8
0-->1-->2-->4-->5-->6-->8
0-->2-->4-->5-->6-->8
0-->1-->2-->3-->5-->6-->8
0-->2-->3-->5-->6-->8
0-->1-->3-->5-->6-->8
0-->1-->2-->3-->4-->6-->8
0-->2-->3-->4-->6-->8
0-->1-->3-->4-->6-->8
0-->1-->2-->4-->6-->8
0-->2-->4-->6-->8
0-->1-->2-->3-->4-->5-->6-->7-->8-->9
0-->2-->3-->4-->5-->6-->7-->8-->9
0-->1-->3-->4-->5-->6-->7-->8-->9
0-->1-->2-->4-->5-->6-->7-->8-->9
0-->2-->4-->5-->6-->7-->8-->9
0-->1-->2-->3-->5-->6-->7-->8-->9
0-->2-->3-->5-->6-->7-->8-->9
0-->1-->3-->5-->6-->7-->8-->9
0-->1-->2-->3-->4-->6-->7-->8-->9
0-->2-->3-->4-->6-->7-->8-->9
0-->1-->3-->4-->6-->7-->8-->9
0-->1-->2-->4-->6-->7-->8-->9
0-->2-->4-->6-->7-->8-->9
0-->1-->2-->3-->4-->5-->7-->8-->9
0-->2-->3-->4-->5-->7-->8-->9
0-->1-->3-->4-->5-->7-->8-->9
0-->1-->2-->4-->5-->7-->8-->9
0-->2-->4-->5-->7-->8-->9
0-->1-->2-->3-->5-->7-->8-->9
0-->2-->3-->5-->7-->8-->9
0-->1-->3-->5-->7-->8-->9
0-->1-->2-->3-->4-->5-->6-->8-->9
0-->2-->3-->4-->5-->6-->8-->9
0-->1-->3-->4-->5-->6-->8-->9
0-->1-->2-->4-->5-->6-->8-->9
0-->2-->4-->5-->6-->8-->9
0-->1-->2-->3-->5-->6-->8-->9
0-->2-->3-->5-->6-->8-->9
0-->1-->3-->5-->6-->8-->9
0-->1-->2-->3-->4-->6-->8-->9
0-->2-->3-->4-->6-->8-->9
0-->1-->3-->4-->6-->8-->9
0-->1-->2-->4-->6-->8-->9
0-->2-->4-->6-->8-->9
0-->1-->2-->3-->4-->5-->6-->7-->9
0-->2-->3-->4-->5-->6-->7-->9
0-->1-->3-->4-->5-->6-->7-->9
0-->1-->2-->4-->5-->6-->7-->9
0-->2-->4-->5-->6-->7-->9
0-->1-->2-->3-->5-->6-->7-->9
0-->2-->3-->5-->6-->7-->9
0-->1-->3-->5-->6-->7-->9
0-->1-->2-->3-->4-->6-->7-->9
0-->2-->3-->4-->6-->7-->9
0-->1-->3-->4-->6-->7-->9
0-->1-->2-->4-->6-->7-->9
0-->2-->4-->6-->7-->9
0-->1-->2-->3-->4-->5-->7-->9
0-->2-->3-->4-->5-->7-->9
0-->1-->3-->4-->5-->7-->9
0-->1-->2-->4-->5-->7-->9
0-->2-->4-->5-->7-->9
0-->1-->2-->3-->5-->7-->9
0-->2-->3-->5-->7-->9
0-->1-->3-->5-->7-->9
0-->1-->2
0-->2
0-->1-->2-->3
0-->2-->3
0-->1-->3
0-->1-->2-->3-->4
0-->2-->3-->4
0-->1-->3-->4
0-->1-->2-->4
0-->2-->4
0-->1-->2-->3-->4-->5
0-->2-->3-->4-->5
0-->1-->3-->4-->5
0-->1-->2-->4-->5
0-->2-->4-->5
0-->1-->2-->3-->5
0-->2-->3-->5
0-->1-->3-->5
0-->1-->2-->3-->4-->5-->6
0-->2-->3-->4-->5-->6
0-->1-->3-->4-->5-->6
0-->1-->2-->4-->5-->6
0-->2-->4-->5-->6
0-->1-->2-->3-->5-->6
0-->2-->3-->5-->6
0-->1-->3-->5-->6
0-->1-->2-->3-->4-->6
0-->2-->3-->4-->6
0-->1-->3-->4-->6
0-->1-->2-->4-->6
0-->2-->4-->6
0-->1-->2-->3-->4-->5-->6-->7
0-->2-->3-->4-->5-->6-->7
0-->1-->3-->4-->5-->6-->7
0-->1-->2-->4-->5-->6-->7
0-->2-->4-->5-->6-->7
0-->1-->2-->3-->5-->6-->7
0-->2-->3-->5-->6-->7
0-->1-->3-->5-->6-->7
0-->1-->2-->3-->4-->6-->7
0-->2-->3-->4-->6-->7
0-->1-->3-->4-->6-->7
0-->1-->2-->4-->6-->7
0-->2-->4-->6-->7
0-->1-->2-->3-->4-->5-->7
0-->2-->3-->4-->5-->7
0-->1-->3-->4-->5-->7
0-->1-->2-->4-->5-->7
0-->2-->4-->5-->7
0-->1-->2-->3-->5-->7
0-->2-->3-->5-->7
0-->1-->3-->5-->7
0-->1-->2-->3-->4-->5-->6-->7-->8
0-->2-->3-->4-->5-->6-->7-->8
0-->1-->3-->4-->5-->6-->7-->8
0-->1-->2-->4-->5-->6-->7-->8
0-->2-->4-->5-->6-->7-->8
0-->1-->2-->3-->5-->6-->7-->8
0-->2-->3-->5-->6-->7-->8
0-->1-->3-->5-->6-->7-->8
0-->1-->2-->3-->4-->6-->7-->8
0-->2-->3-->4-->6-->7-->8
0-->1-->3-->4-->6-->7-->8
0-->1-->2-->4-->6-->7-->8
0-->2-->4-->6-->7-->8
0-->1-->2-->3-->4-->5-->7-->8
0-->2-->3-->4-->5-->7-->8
0-->1-->3-->4-->5-->7-->8
0-->1-->2-->4-->5-->7-->8
0-->2-->4-->5-->7-->8
0-->1-->2-->3-->5-->7-->8
0-->2-->3-->5-->7-->8
0-->1-->3-->5-->7-->8
0-->1-->2-->3-->4-->5-->6-->8
0-->2-->3-->4-->5-->6-->8
0-->1-->3-->4-->5-->6-->8
0-->1-->2-->4-->5-->6-->8
0-->2-->4-->5-->6-->8
0-->1-->2-->3-->5-->6-->8
0-->2-->3-->5-->6-->8
0-->1-->3-->5-->6-->8
0-->1-->2-->3-->4-->6-->8
0-->2-->3-->4-->6-->8
0-->1-->3-->4-->6-->8
0-->1-->2-->4-->6-->8
0-->2-->4-->6-->8
0-->1-->2-->3-->4-->5-->6-->7-->8-->9
0-->2-->3-->4-->5-->6-->7-->8-->9
0-->1-->3-->4-->5-->6-->7-->8-->9
0-->1-->2-->4-->5-->6-->7-->8-->9
0-->2-->4-->5-->6-->7-->8-->9
0-->1-->2-->3-->5-->6-->7-->8-->9
0-->2-->3-->5-->6-->7-->8-->9
0-->1-->3-->5-->6-->7-->8-->9
0-->1-->2-->3-->4-->6-->7-->8-->9
0-->2-->3-->4-->6-->7-->8-->9
0-->1-->3-->4-->6-->7-->8-->9
0-->1-->2-->4-->6-->7-->8-->9
0-->2-->4-->6-->7-->8-->9
0-->1-->2-->3-->4-->5-->7-->8-->9
0-->2-->3-->4-->5-->7-->8-->9
0-->1-->3-->4-->5-->7-->8-->9
0-->1-->2-->4-->5-->7-->8-->9
0-->2-->4-->5-->7-->8-->9
0-->1-->2-->3-->5-->7-->8-->9
0-->2-->3-->5-->7-->8-->9
0-->1-->3-->5-->7-->8-->9
0-->1-->2-->3-->4-->5-->6-->8-->9
0-->2-->3-->4-->5-->6-->8-->9
0-->1-->3-->4-->5-->6-->8-->9
0-->1-->2-->4-->5-->6-->8-->9
0-->2-->4-->5-->6-->8-->9
0-->1-->2-->3-->5-->6-->8-->9
0-->2-->3-->5-->6-->8-->9
0-->1-->3-->5-->6-->8-->9
0-->1-->2-->3-->4-->6-->8-->9
0-->2-->3-->4-->6-->8-->9
0-->1-->3-->4-->6-->8-->9
0-->1-->2-->4-->6-->8-->9
0-->2-->4-->6-->8-->9
0-->1-->2-->3-->4-->5-->6-->7-->9
0-->2-->3-->4-->5-->6-->7-->9
0-->1-->3-->4-->5-->6-->7-->9
0-->1-->2-->4-->5-->6-->7-->9
0-->2-->4-->5-->6-->7-->9
0-->1-->2-->3-->5-->6-->7-->9
0-->2-->3-->5-->6-->7-->9
0-->1-->3-->5-->6-->7-->9
0-->1-->2-->3-->4-->6-->7-->9
0-->2-->3-->4-->6-->7-->9
0-->1-->3-->4-->6-->7-->9
0-->1-->2-->4-->6-->7-->9
0-->2-->4-->6-->7-->9
0-->1-->2-->3-->4-->5-->7-->9
0-->2-->3-->4-->5-->7-->9
0-->1-->3-->4-->5-->7-->9
0-->1-->2-->4-->5-->7-->9
0-->2-->4-->5-->7-->9
0-->1-->2-->3-->5-->7-->9
0-->2-->3-->5-->7-->9
0-->1-->3-->5-->7-->9
为做纪念,所以贴出来算了。