zoukankan      html  css  js  c++  java
  • 打印0-n的所有路径【原创】

      几天在论坛,看到这么个题目:
        
      打印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(
    01);

            addProcessInfo(
    02);
            addProcessInfo(
    12);
            addProcessInfo(
    13);

            addProcessInfo(
    23);

            addProcessInfo(
    24);
            addProcessInfo(
    34);
            addProcessInfo(
    35);

            addProcessInfo(
    45);

            addProcessInfo(
    46);
            addProcessInfo(
    56);
            addProcessInfo(
    57);

            addProcessInfo(
    67);

            addProcessInfo(
    68);
            addProcessInfo(
    78);
            addProcessInfo(
    79);

            addProcessInfo(
    89);
        }


        
    /**
         * 增加路径信息到数组中
         * 
         * 
    @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

      为做纪念,所以贴出来算了。
  • 相关阅读:
    ASP.NET获取服务器信息
    检测到有潜在危险的 Request.Form 值错误解决办法
    修改sql server数据库逻辑文件名的语句
    遍历类的所有属性和根据属性名动态设置属性值
    JS三种编解码方式
    获取QQ群用户列表
    关于字符串类型相关的问题总结
    学习C++之父的最新姐妹作笔记1
    【转】 Uniode TO ANSI 转换函数封装
    添加工具栏图标按钮(转)
  • 原文地址:https://www.cnblogs.com/zxub/p/461163.html
Copyright © 2011-2022 走看看