基础集路径算法中的错误/错误我无法弄清楚

时间:2010-03-25 01:30:52

标签: c++

以下内容通过2d数组查找基本集路径。它应该打印出各个路径但不重复任何路径,并在找到所有路径时结束。然而它并没有停在最后一条路径上并且在其中发生以下情况的地方有一个错误:它走到路径的中途然后变为零并且由于某种原因结束路径。

例如,表中填充了以下内容: 全部为0,

除外

[1] [2],[1] [3],[2] [4],[2] [5],[3] [5],[4] [6],[5] [6 ],[6] [0]

其中都有一个。期望的路径是 P1:1 2 4 6 0

P2:1 3 5 6 0

P3:1 2 5 6 0.

我运行程序时得到的输出是 12460

13560

1250

124

非常感谢任何和所有这方面的帮助,这只是扫描数组寻找路径的函数,我可以添加整个程序,如果这将有所帮助。感谢..

void find_path(int map[][MAX], int x){
 int path =0;
 int m=1;
 int blah=0;
 bool path_found = false;

 do
 {
  for(int n=0;n<(x+1);n++){
   if(map[m][n]==-1){
    blah=(n+1);
    if(blah<(x+1)){
     for(blah;blah<(x+1);blah++){
      if(map[m][blah]==1){
       map[m][blah]=-1;
       path=m;
       path_found = true;
       cout<<path;
       m=blah;
       n=0;
      }
     }
    }
    else{  
    path=m;
    path_found=false;
    cout<<path;
    m=n;
    if(m==0){
     path=0;
     cout<<path<<endl;
     m=1;
     path_found=false;
     }
    } 
   }
   else if(map[m][n]==1){
    map[m][n]=-1;
    path=m;
    path_found = true;
    cout<<path;
    m=n;
    if(m==0){
     path=0;
     cout<<path<<endl;
     m=1;
     path_found=false;
    }
   }

  }
 } 
 while(m<(x+1) && path_found);
}

3 个答案:

答案 0 :(得分:3)

你犯了一个太常见的错误。有太多人认为编写软件的主要目的是告诉计算机该做什么。那是不对的。主要目标是将 CLEARLY 与其他人进行沟通。次要目标是告诉计算机该做什么。

我建议你不要使用硬编码的数字(map [] [] = - 1中的-1)。枚举就是为此而制作的。变量名称可能更具描述性。 (“等等”?)你可以将条款留空,例如for(; blah&lt;(x + 1); blah ++)。 (即使for(;;)有效。)通常数组从0..LIMIT-1开始,所以你可以说(; blah&lt; x; ++ blah)。通常++ foo比foo ++更受欢迎,尽管它与int有很大不同。注意名字中的下划线。很容易混淆path-found和path_found。 添加评论!!! 解释您在做什么。在你的时候添加空格。紧凑的代码是没有人的朋友。至少,记录您正在改变MAP中的值。

所有这一切......从哪里开始...

好吧,在更改节点后,我已经从第一个路径选项开始,而不是在当前节点加1.(例如,从1到2跳转,从2到4,然后你开始看地图[4] [5]而不是地图[4] [0]或地图[4] [1]。

我不会将特殊的套装0作为退出标准。

您的行“for(blah; blah&lt;(x + 1); blah ++){”在找到map [m] [blah] == 1匹配时不退出(break),但将其标记为-1并继续寻找其他比赛。这应该用先前的“for(int n = 0; n&lt;(x + 1); n ++){”行创建一个有趣的效果。

一旦你达到M = 6,N = 1你就永远不会达到你的特殊套装0退出标准并打印出来。 (你确实知道你有n = 0,然后是n ++ ???

一旦你的地图满了-1,你就永远无法继续前进。当您的某些路径共享相同的链接时,这是一个真正的问题。例如。 1-2-4-6-0和1-3-5-6-0分享6-0。

您没有检测到满-1的地图。你有一个无限循环。 (如果要将path_found设置为false,请在“do {”之后立即执行,“for(int n = 0; n&lt;(x + 1); n ++){”。不要在某些容易错过的退出点深处在嵌套的if语句中。

运行程序时,我看不到输出 12460,13560,1250,124 。我看到 12460,135 ,然后挂起。 (而且只有在我修改你的软件以在每次写入后刷新输出之后)。

您没有显示脚手架代码。类似的东西:

void printMap(int theMap[][MAX] )
{
  for( int i=0; i<MAX; ++i )
  {
    cout << "[" << i << "] ";
    for ( int j=0;  j<MAX;  ++j )
      cout << "  " << theMap [i] [j];
    cout << endl;
  }  /* for( int i=0; i<MAX; ++i )  */
  cout << endl;
}

加上调试器(在gdb中使用“call printMap(map)”)会对你有所帮助。 (这当然是给我的。)

您的代码会复制自己。这通常是一个错误的迹象。例如。 “if(m == 0){path = 0; cout&lt;&lt; path&lt;&lt; endl; m = 1; path_found = false;}”位。或者“if(map [m] [FOO] == 1){map [m] [FOO] = - 1; path = m; path_found = true; cout&lt;&lt; path; m = FOO;”部分,其中FOO是“blah”或“n”。


所有这些说,我不得不处理更糟糕的代码(在专业情况下也不少)。 (不常见,但确实会发生。)坚持下去,你会变得更好。我们都是在同一个不好的地方开始的。练习,不断提问,你会改进。



在这里回复评论......

  
    

我在那里遇到特殊情况0的唯一原因是因为当它达到0时它才挂起,因为该行是空的并且它处于无限循环中。

  

您需要对退出条件进行更好的测试。

  
    

当我编译并运行它时,我得到了我描述的输出,而不是你得到的输出。

  

我使用g ++版本3.4.4:

#define MAX 7
                      /* 0  1  2  3  4  5  6 */
int  map[MAX][MAX] = { { 0, 0, 0, 0, 0, 0, 0 }, /*0*/
                       { 0, 0, 1, 1, 0, 0, 0 }, /*1*/
                       { 0, 0, 0, 0, 1, 1, 0 }, /*2*/
                       { 0, 0, 0, 0, 0, 1, 0 }, /*3*/
                       { 0, 0, 0, 0, 0, 0, 1 }, /*4*/
                       { 0, 0, 0, 0, 0, 0, 1 }, /*5*/
                       { 1, 0, 0, 0, 0, 0, 0 }  /*6*/
                     };

find_path( map, 6 );

也许您的输入条件不同?

  
    

我不明白为什么它会达到m = 6 n = 1,除了[6] [0]之外,该行的其余部分为0。

  

以下代码属于您(具有轻微的外观变化)。

N = 0出现在Line = 25处。当Line = 16的for循环完成时,我们在Line = 9处恢复for循环。第一步是最终迭代(n ++)组件。因此,Line = 10处的下一个for循环迭代具有m = blah = 6且n = 1。在这个阶段,你的条件测试(== - 1,== 1)都不可能是真的。

你真的应该尝试在调试器中单步执行代码。查看代码实际执行的操作与您预期的操作。

/* 0*/   void find_path( int map[][MAX], int x )
/* 1*/   {
/* 2*/     int  path = 0;
/* 3*/     int  m    = 1;
/* 4*/     int  blah = 0;
/* 5*/     bool path_found = false;
/* 6*/   
/* 7*/     do
/* 8*/     {
/* 9*/       for ( int n=0;  n < (x+1);  n++ )
/*10*/       {
/*11*/         if ( map [m] [n] == -1 )
/*12*/         {
/*13*/           blah = (n+1);
/*14*/           if ( blah < (x+1) )
/*15*/           {
/*16*/             for ( ;  blah < (x+1);  blah++ )
/*17*/             {
/*18*/               if ( map [m] [blah] == 1 )
/*19*/               {
/*20*/                 map [m] [blah] = -1;
/*21*/                 path = m;
/*22*/                 path_found = true;
/*23*/                 cout << path;
/*24*/                 m = blah;
/*25*/                 n = 0;
/*26*/               } /* if ( map [m] [blah] == 1 ) */
/*27*/             } /* for ( ;  blah < (x+1);  blah++ ) */
/*28*/           } /* if ( blah < (x+1) ) */
/*29*/           else
/*30*/           {
/*31*/             path = m;
/*32*/             path_found = false;
/*33*/             cout << path;
/*34*/             m = n;
/*35*/             if ( m == 0 )
/*36*/             {
/*37*/               path = 0;
/*38*/               cout << path << endl;
/*39*/               m = 1;
/*40*/               path_found = false;
/*41*/             } /* if ( m == 0 ) */
/*42*/           } /* if ( blah < (x+1) ) ... ELSE ... */
/*43*/         } /* if ( map [m] [n] == -1 ) */
/*44*/         else if ( map [m] [n] == 1 )
/*45*/         {
/*46*/           map [m] [n] = -1;
/*47*/           path = m;
/*48*/           path_found = true;
/*49*/           cout << path;
/*50*/           m = n;
/*51*/           if ( m == 0 )
/*52*/           {
/*53*/             path = 0;
/*54*/             cout << path << endl;
/*55*/             m = 1;
/*56*/             path_found = false;
/*57*/           } /* if ( m == 0 ) */
/*58*/         } /* if(map[m][n]==-1) ... ELSE IF (map[m][n]==1) ... */
/*59*/         
/*60*/       } /* for ( int n=0;  n < (x+1);  n++ ) */
/*61*/       
/*62*/     } /* do { ... } */ while(m<(x+1) && path_found);
/*63*/     
/*64*/   } /* void find_path( int map[][MAX], int x ) */

答案 1 :(得分:0)

当我使用您发布的代码编译函数时,我得到12460作为输出,然后它挂起无限循环,除非我取出if(blah&lt;(x + 1)和相应的else,然后我得到我首先描述的输出。

我已经尝试过这个并提出以下内容,它给了我124601356作为输出然后结束。

void find_path(int map[][MAX], int x){
    int path =0;
    int m=1;
    int rest_of_row=0;
    bool path_found;
    do
    {
        path_found = false;
        for(int n=0;n<(x+1);n++){
            //check to see if the node is already used on a path
            if(map[m][n]==-1){
                rest_of_row=(n+1);
                path=m;

                //check to see there are any unused nodes for the path from found node +1 to end of row
                do{
                    if(map[m][rest_of_row]==1){
                        map[m][rest_of_row]=-1;
                        path_found = true;
                    }
                    else{
                        ++rest_of_row;
                    }
                }
                while(!path_found);

                m=n;


                if(path_found){
                    m=(rest_of_row);
                }

                cout<<path;
            }
            //else check to see if the node hasn't been used in the path
            else if(map[m][n]==1){
                map[m][n]=-1;
                path=m;
                path_found = true;
                cout<<path;
                m=n;
            }
            //if the node is at 0 path is complete, go back to 1 to check for new path
            if(m==0){
                path=m;
                m=1;
                path_found=false;
                cout<<path;
            }
        }
    }
    while(m<(x+1) && path_found);

}

答案 2 :(得分:0)

这是工作代码(使用足够先进的C ++,你无法将它作为自己的工作交付,也要感谢mrree,从他的回答我“解除了”地图的初始化程序)。我建议你更深入地思考这个问题,从我为什么正确的解决方案使用递归开始,你的既没有递归也没有堆栈。我认为实际上可以避免堆栈,因为路径数组具有回溯所需的所有状态,但你肯定需要某种形式的回溯。

// enumpaths.cpp : Prints all longest paths given a digraph connectivity matrix
//

const size_t MAX = 7;

typedef void (*path_completed_cb)( const size_t (&path)[MAX], size_t const currentLength );

void follow_path( size_t (&path)[MAX], size_t const currentLength, const bool (&map)[MAX][MAX], path_completed_cb const callback )
{
 size_t currentEnd = path[currentLength-1];

 /* check for loops, if a loop exists then every finite path is
    a subpath of a longer (looped more often) path */
 for( size_t i = 0; i < currentLength; i++ ) {
  if (map[currentEnd][path[i]]) return; /* found a loop */
 }

 bool extended = false;
 /* look for continuances */
 for( size_t next = 0; next < MAX; next++ ) {
  if (map[currentEnd][next]) {
   extended = true;
   path[currentLength] = next;
   follow_path(path, currentLength+1, map, callback);
  }

 }
 if (!extended) {
  /* there were no outgoing arcs, this is a longest path */
  (*callback)(path, currentLength);
 }
}

void enum_paths( const bool (&map)[MAX][MAX], path_completed_cb const callback )
{
 for ( size_t start = 0; start < MAX; start++ ) {
  bool isSource = true;
  /* if any incoming arcs to node "start", then any paths
     starting at start are subpaths of longer paths */
  for (size_t pred = 0; pred < MAX; pred++ )
   if (map[pred][start]) isSource = false;

  if (isSource) {
   size_t path[MAX] = { start };
   follow_path(path, 1, map, callback);
  }
 }
}

#include <iostream>
#include <iomanip>

void print_path( const size_t (&path)[MAX], size_t const currentLength )
{
 using namespace std;
 cout << path[0];
 for( size_t i = 1; i < currentLength; i++ ) {
  cout << '-' << path[i];
 }
 cout << endl;
}

int main()
{                   
 const bool map[MAX][MAX] =
  /* 0  1  2  3  4  5  6 */
 { { 0, 0, 0, 0, 0, 0, 0 }, /*0*/
   { 0, 0, 1, 1, 0, 0, 0 }, /*1*/
   { 0, 0, 0, 0, 1, 1, 0 }, /*2*/
   { 0, 0, 0, 0, 0, 1, 0 }, /*3*/
   { 0, 0, 0, 0, 0, 0, 1 }, /*4*/
   { 0, 0, 0, 0, 0, 0, 1 }, /*5*/
   { 1, 0, 0, 0, 0, 0, 0 }  /*6*/
 };

 enum_paths(map, &print_path);

 return 0;
}
编辑:尝试没有递归,并且只是简单地删除递归将只是一个机械转换,在不引入gotos的情况下这样做并不容易。也没有将“开始路径”案例与“中间路径”逻辑合并。