LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4084|回复: 37

过河问题!!!大家帮忙看看

[复制链接]
发表于 2003-5-18 10:44:59 | 显示全部楼层 |阅读模式
我在写老师布置的数据结构作业,题目是这样的
1、问题描述
   假若有n个正常人和n个精神病患者准备过河,但只有一条能容纳c个人的小船,为了防止精神病人侵犯正常人,要求无论在何处,正常人的人数不得少于精神病患者的人数(除正常人人数为零),且假定两种人都会划船,试设计一个算法,确定他们是否能渡过河去,若能,则给出一只小船来回次数最少的最佳方案。

2、基本要求
   输入:正常人人数(即精神病患者人数)n。小船一次最多载客人数c。
   输出:若问题无解,则显示渡河失败信息,否则,输出一组最佳答案,用三元组(x1,x2,x3)表示渡河过程中的状态。并用箭头输出这些状态之间的迁移。
   其中:x1表示当前岸上的正常人人数,x2表示当前岸上的精神病人人数,x3表示小船的位置(0表示目的岸,1表示起始岸)。

3、算法思想:

(1)算法思想
  1)建立空队列,将起始状态入队列
  2)取出对头元素,根据“基本要求”产生各种可能的状态,由判断合法条件:x1==0或x1==n或x1==x2判断各种状态的可达、合法性,将可达、合法的状态入队列。如果所入队列状态为目标状态,则搜索成功,转3)
  3)按目标状态<-.......<-起始状态的顺序将渡河过程输出,成功退出。
  4)若没有产生出目标状态,则失败退出。

(2)数据结构
    用双链表作为队列
  typedef struct node
   {
        int a,b,c,no,prec;
        struct node *pre;
        struct node *next;
   }qu;
   
   typedef struct
   {
       qu *front,*rear;
   }op;

4、运行结果
    以正常人和精神病患者人数都为2,小船一次最多载人人数为2为例,程序运行结果为:
    x1   x2   x3   no   prec
      2, 2, 0,  8, 7       (目标状态)
    1, 1, 1,  7, 6
      2, 1, 0,  6, 5
      2, 1, 1,  5, 2
      0, 2, 0,  2, 1
      2, 2, 1,  1, 0       (起始状态)

    x1表示当前岸上正常人人数,x2表示当前岸上精神病人人数,x3表示小船位置,no表示状态编号,prec表示当前状态的前趋。

以上就是题目,我写了一个程序,想来想去都没问题了,编译连接也没问题,但是运行以后windows就跳出一个窗口,说 NTVDM CPU 遇到无效的指令。
               cs:0000  IP:0077  OP:f0 37 05 12 02
天那
不明白怎么回事了,望各位救救我啊~~~~~~~~~~~~~~~
不胜感激!!!

我写的程序如下:


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>

  4. typedef
  5. struct node
  6. {
  7.   int             a;
  8.   int             b;
  9.   int             c;
  10.   int            no;
  11.   int          prec;

  12.   struct node *next;
  13.   struct node * pre;
  14. }
  15. qu;

  16. typedef
  17. struct
  18. {
  19.   qu *front;
  20.   qu * rear;
  21. }
  22. op;                                  /*以上定义了两个结构体,分别作为链节点 和 指示首尾的标志*/


  23.                                      /*正常人人数(即精神病人数)*/
  24. int n;                               /*小船最大载客数*/
  25. int c;                               /*定义的用来在born()函数中记录产生多少子状态的全局变量*/
  26. int sonnum;


  27. qu *redBox;                          /*用来放置初始状态*/
  28. op *  flag;                          /*指示链队列*/


  29. void  enqueue( qu * );               /*三个函数声明(declaration)*/
  30. qu **    born( qu * );               /*分别代表 入队、衍生、打印*/
  31. void      prt( void );


  32. int main(void)                       /*主函数*/
  33. {
  34.     int bank = 1;                    /*指示当前岸*/
  35.     int count;                       /*后面要用到的一个计数变量*/

  36.     qu *  seed;                      /*用来给born()带去入口参数*/
  37.     qu ** tree;                      /*用来放置衍生出来的状态*/

  38.   input:                                      /*用户输入数据*/
  39.     printf("\nPlease input the N:");
  40.     scanf("%d", &n);
  41.     printf("\nPlease input the C:");
  42.     scanf("%d", &c);

  43.     if( n<1 || c<=1 )                              /*判断是否合法,若非法则重新输入*/
  44.     {
  45.        printf("\nBad data!\nPlease re-input.\n");
  46.        goto input;
  47.     }

  48.     flag->front       = (qu *)malloc( sizeof(qu) );    /*建立空队列*/
  49.     flag->rear        = flag->front;
  50.     flag->front->pre  = NULL;
  51.     flag->front->next = NULL;

  52.     redBox = (qu *)malloc( sizeof(qu) );             /*诞生初始状态*/
  53.     redBox->a    = n;
  54.     redBox->b    = n;
  55.     redBox->c    = 1;
  56.     redBox->no   = 1;
  57.     redBox->prec = 0;

  58.     redBox->next      = flag->front->next;           /*初始状态入队列*/
  59.     redBox->pre       = flag->front;
  60.     flag->front->next = redBox;
  61.     flag->rear        = redBox;

  62.     if(    flag->front->next->a == n                 /*判断队首元素(非对头)是否目标状态*/
  63.         && flag->front->next->b == n
  64.         && flag->front->next->c == 0
  65.       )
  66.     prt();                                           /*若是目标状态则打印*/

  67.     seed = flag->front->next;                        /*用seed先指向队首元素*/

  68.     while( seed != flag->front )                     /*队首元素产生子状态入队,子状态再产生子状态入队*/
  69.     {                                                /*如此往复,直到seed指向对头元素*/
  70.        while( seed->c == bank )                      /*当前岸相同的连续若干状态*/
  71.        {
  72.            tree = born( seed );                      /*产生子状态*/

  73.            for( count=0; count<sonnum; count++ )     /*产生多少状态(由sonnum从born()中得到)就入几次队列*/
  74.            {
  75.               enqueue( tree[count] );                /*入队*/

  76.               if(    flag->front->next->a == n
  77.                   && flag->front->next->b == n
  78.                   && flag->front->next->c == 0
  79.                 )
  80.               prt();                                 /*判断是否目标状态,是则打印*/
  81.            }
  82.            seed = seed->pre;                         /*seed向前挪一格*/
  83.        }
  84.        bank = !bank;                                 /*到下一相同岸连续状态区间内,bank改变*/
  85.     }

  86.     printf("\nThere is no way to let them pass the river!\n");    /*若以上没有产生目标状态,提示无结果*/

  87.     getch();
  88.     return 0;                                                     /*无结果结束*/

  89. }


  90. void enqueue( qu *grayBox )                            /*定义入队列函数*/
  91. {
  92.     grayBox->next = flag->front->next;
  93.     grayBox->pre  = flag->front;

  94.     flag->front->next->pre = grayBox;
  95.     flag->front->next      = grayBox;
  96. }

  97. qu **born( qu *parent )                               /*定义衍生函数*/
  98. {
  99.    qu **      son;          /*把son = NULL的话,就不会出现警告了,但是运行窗口就“死”了*/
  100.    qu  *  grandpa;                      /*指向当前状态的前趋状态*/
  101.    qu  *    light;                      /*搜索用的指针变量*/

  102.    int counter1;
  103.    int counter2;
  104.    int counter = 0;                           /*三个计数变量,分别代表a,b和产生合法状态数*/

  105.    int num =   parent->no;                       /*当前状态序号,准备给产生子状态编号和前趋号用*/
  106.    int b   = !(parent->c);                       /*产生的子状态都是在当前状态的对岸*/

  107.    light = flag->rear;                           /*light指向队尾*/
  108.    while( light != flag->front )                 /*搜索整个队列,根据当前状态的前趋号找当前状态的父状态节点*/
  109.    {
  110.       if( light->no == parent->prec )
  111.         grandpa = light;

  112.       light = light->pre;
  113.    }

  114.    for( counter1=0; counter1<n; counter1++ )                  /*用双重循环产生当前状态可能产生的各种*/
  115.    {                                                          /*状态,再用几个if去掉当前状态的父状态*/
  116.       for( counter2=0; counter2<n; counter2++ )                       /* 和非法的状态 */
  117.       {
  118.          if( counter1==0 || counter1==n || counter1==counter2 )    /*见基本要求*/
  119.          {
  120.             if( abs( (n-counter1)+(n-counter2)-(2*n) ) <= c )      /*一个岸一次的人数变化应小于等于最大船载数*/
  121.             {
  122.                if( counter1 == grandpa->a && counter2 == grandpa->b )  /*去掉当前状态的父状态*/
  123.                  continue;
  124.                son[counter] = (qu *)malloc( sizeof(qu) );              /*产生新状态*/

  125.                son[counter]->a    = counter1;
  126.                son[counter]->b    = counter2;
  127.                son[counter]->c    = b;
  128.                son[counter]->prec = parent->no;
  129.                son[counter]->no   = (++num);

  130.                counter++;                                       /*记录产生了多少个子状态*/
  131.             }
  132.          }
  133.       }
  134.    }

  135.    sonnum = counter;                                         /*把总共产生多少个子状态传递给全局变量*/
  136.                                                              /*给main中while循环*/
  137.    return son;                                               /*返回指向子状态的指针数组的首地址*/
  138. }


  139. void prt( void )                                             /*定义打印函数*/
  140. {
  141.    int  temp = flag->front->next->prec;                      /*获得目标状态前趋号*/
  142.    qu * feet;                                                /*搜索用的指针*/

  143.    feet = flag->front->next;                                 /*先指向对首的目标状态*/

  144.    printf("\nX1  X2  X3  No  Prec\n");
  145.    printf("%d  %d  %d  %d  %d\n",                            /*先打印出目标状态*/
  146.            flag->front->next->a,
  147.            flag->front->next->b,
  148.            flag->front->next->c,
  149.            flag->front->next->no,
  150.            flag->front->next->pre
  151.          );

  152.    while( feet != flag->rear->next )                        /*根据前趋号来搜索路径*/
  153.    {
  154.        if( feet->no == temp )
  155.        {
  156.           printf("%d  %d  %d  %d  %d\n",
  157.                   feet->a,
  158.                   feet->b,
  159.                   feet->c,
  160.                   feet->no,
  161.                   feet->prec
  162.                 );
  163.           temp = feet->prec;
  164.        }

  165.        feet = feet->next;
  166.    }
  167.    exit (0);                                          /*搜索成功退出*/
  168. }
复制代码

 楼主| 发表于 2003-5-18 10:52:32 | 显示全部楼层
我靠!发帖以后格式怎么一塌糊涂啊

大家看看这里吧
http://www.ka163.net/vcok/bbs/dispbbs.asp?boardID=1&ID=7471
 楼主| 发表于 2003-5-18 12:18:45 | 显示全部楼层
我顶!
大家帮帮忙啊~~~~~~~~
谢谢!!!
 楼主| 发表于 2003-5-19 19:10:47 | 显示全部楼层
我再顶!!
大家帮帮忙啊
就你一时解决不了
至少帮我顶一下啊
谢谢!!!!
 楼主| 发表于 2003-5-19 19:14:12 | 显示全部楼层
我没有加上
  1. ...
复制代码

来显示正常的缩进格式
现在已经过了编辑期限
请管理员帮个忙
谢谢!
发表于 2003-5-19 19:19:27 | 显示全部楼层
已经加了。
 楼主| 发表于 2003-5-19 19:35:38 | 显示全部楼层
谢谢!!
当然如果kj兄这种高手再帮忙看看就好了
非常感谢!!
发表于 2003-5-19 19:38:09 | 显示全部楼层
这两天忙于整理论坛,有时间再给你看看吧。
 楼主| 发表于 2003-5-19 19:42:09 | 显示全部楼层
好的好的,不要紧
你忙你的,只是要记得有空看下
谢谢kj兄啊
真够兄弟!!
 楼主| 发表于 2003-5-19 19:49:28 | 显示全部楼层
另外后来又改了两处错误
也过了编辑期限了,
一是:在main函数的第一个if语句后面的建立空队列部分没有为flag
分配内存空间,前面加一句:
flag    =     (op*)malloc( sizeof(op) );

二是:在born函数中的为grandpa赋值部分改为:
  1.       if( light->no == parent->prec )
  2.         {
  3.             grandpa = light;
  4.             break;                                     /*赋值以后就跳出循环*/
  5.         }  
复制代码

可以见我第一个回复中给出的连接
谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表