查看全部128种考试
1
2
3
4
5
6
7
8
9
10
xihuyu2000  
【字体: 常用算法设计方法
常用算法设计方法
djks.exam8.com 来源:老顽童 更新:2005-4-20 17:27:00 计算机等级考试 考试论坛

【问题】       n皇后问题

    问题描述:求出在一个n×n的棋盘上,放置n个不能互相捕捉的国际象棋“皇后”的所有布局。

       这是来源于国际象棋的一个问题。皇后可以沿着纵横和两条斜线4个方向相互捕捉。如图所示,一个皇后放在棋盘的第4行第3列位置上,则棋盘上凡打“×”的位置上的皇后就能与这个皇后相互捕捉。

      

1

2

3

4

5

6

7

8

 

 

×

 

 

×

 

 

×

 

×

 

×

 

 

 

 

×

×

×

 

 

 

 

×

×

Q

×

×

×

×

×

 

×

×

×

 

 

 

 

×

 

×

 

×

 

 

 

 

 

×

 

 

×

 

 

 

 

×

 

 

 

×

 

    从图中可以得到以下启示:一个合适的解应是在每列、每行上只有一个皇后,且一条斜线上也只有一个皇后。

       求解过程从空配置开始。在第1列至第m列为合理配置的基础上,再配置第m+1列,直至第n列配置也是合理时,就找到了一个解。接着改变第n列配置,希望获得下一个解。另外,在任一列上,可能有n种配置。开始时配置在第1行,以后改变时,顺次选择第2行、第3行、…、直到第n行。当第n行配置也找不到一个合理的配置时,就要回溯,去改变前一列的配置。得到求解皇后问题的算法如下:

       {     输入棋盘大小值n

              m=0;

              good=1;

              do {

                     if (good)

                            if (m==n)

                            {     输出解;

                                   改变之,形成下一个候选解;

                            }

                            else  扩展当前候选接至下一列;

                     else  改变之,形成下一个候选解;

                     good=检查当前候选解的合理性;

              } while (m!=0);

       }

       在编写程序之前,先确定边式棋盘的数据结构。比较直观的方法是采用一个二维数组,但仔细观察就会发现,这种表示方法给调整候选解及检查其合理性带来困难。更好的方法乃是尽可能直接表示那些常用的信息。对于本题来说,“常用信息”并不是皇后的具体位置,而是“一个皇后是否已经在某行和某条斜线合理地安置好了”。因在某一列上恰好放一个皇后,引入一个一维数组(col[ ]),值col[i]表示在棋盘第i列、col[i]行有一个皇后。例如:col[3]=4,就表示在棋盘的第3列、第4行上有一个皇后。另外,为了使程序在找完了全部解后回溯到最初位置,设定col[0]的初值为0当回溯到第0列时,说明程序已求得全部解,结束程序运行。

       为使程序在检查皇后配置的合理性方面简易方便,引入以下三个工作数组:

(1)       数组a[ ]a[k]表示第k行上还没有皇后;

(2)       数组b[ ]b[k]表示第k列右高左低斜线上没有皇后;

(3)       数组 c[ ]c[k]表示第k列左高右低斜线上没有皇后;

    棋盘中同一右高左低斜线上的方格,他们的行号与列号之和相同;同一左高右低斜线上的方格,他们的行号与列号之差均相同。

       初始时,所有行和斜线上均没有皇后,从第1列的第1行配置第一个皇后开始,在第mcol[m]行放置了一个合理的皇后后,准备考察第m+1列时,在数组a[ ]b[ ]c[ ]中为第m列,col[m]行的位置设定有皇后标志;当从第m列回溯到第m-1列,并准备调整第m-1列的皇后配置时,清除在数组a[ ]b[ ]c[ ]中设置的关于第m-1列,col[m-1]行有皇后的标志。一个皇后在m列,col[m]行方格内配置是合理的,由数组a[ ]b[ ]c[ ]对应位置的值都为1来确定。细节见以下程序:

【程序】

# include <stdio.h>

# include <stdlib.h>

# define   MAXN    20

int n,m,good;

int col[MAXN+1],a[MAXN+1],b[2*MAXN+1],c[2*MAXN+1];

 

void main()

{     int j;

       char awn;

       printf(“Enter n:    “);   scanf(“%d”,&n);

       for (j=0;j<=n;j++)   a[j]=1;

       for (j=0;j<=2*n;j++)      cb[j]=c[j]=1;

       m=1;       col[1]=1;        good=1;  col[0]=0;

       do {

              if (good)

                     if (m==n)

                     {     printf(“\t”);

                            for (j=1;j<=n;j++)

                                   printf(“%3d\t%d\n”,j,col[j]);

                            printf(“Enter  a  character (Q/q  for  exit)!\n”);

                            scanf(“%c”,&awn);

                            if (awn==’Q’||awn==’q’)      exit(0);

                            while (col[m]==n)

                            {     m--;

                                   a[col[m]]=b[m+col[m]]=c[n+m-col[m]]=1;

                            }

                            col[m]++;

                     }

                     else

                     {     a[col[m]]=b[m+col[m]]=c[n+m-col[m]]=0;

                            col[++m]=1;

                     }

              else

              {     while (col[m]==n)

                     {     m--;

                            a[col[m]]=b[m+col[m]]=c[n+m-col[m]]=1;

                     }

                     col[m]++;

              }

              good=a[col[m]]&&b[m+col[m]]&&c[n+m-col[m]];

       } while (m!=0);

}

       试探法找解算法也常常被编写成递归函数,下面两程序中的函数queen_all()和函数queen_one()能分别用来解皇后问题的全部解和一个解。

【程序】

# include <stdio.h>

# include <stdlib.h>

# define   MAXN    20

int n;

int col[MAXN+1],a[MAXN+1],b[2*MAXN+1],c[2*MAXN+1];

void main()

{     int j;

       printf(“Enter n:    “);   scanf(“%d”,&n);

       for (j=0;j<=n;j++)   a[j]=1;

       for (j=0;j<=2*n;j++)      cb[j]=c[j]=1;

       queen_all(1,n);

}

 

void queen_all(int k,int n)

{     int i,j;

       char awn;

       for (i=1;i<=n;i++)

              if (a[i]&&b[k+i]&&c[n+k-i])

              {     col[k]=i;

                     a[i]=b[k+i]=c[n+k-i]=0;

                     if (k==n)

                     {     printf(“\t”);

                            for (j=1;j<=n;j++)

                                   printf(“%3d\t%d\n”,j,col[j]);

                            printf(“Enter  a  character (Q/q  for  exit)!\n”);

                            scanf(“%c”,&awn);

                            if (awn==’Q’||awn==’q’)      exit(0);

                     }

                     queen_all(k+1,n);

                     a[i]=b[k+i]=c[n+k-i];

              }

}

       采用递归方法找一个解与找全部解稍有不同,在找一个解的算法中,递归算法要对当前候选解最终是否能成为解要有回答。当它成为最终解时,递归函数就不再递归试探,立即返回;若不能成为解,就得继续试探。设函数queen_one()返回1表示找到解,返回0表示当前候选解不能成为解。细节见以下函数。

【程序】

# define   MAXN    20

       int n;

       int col[MAXN+1],a[MAXN+1],b[2*MAXN+1],c[2*MAXN+1];

       int queen_one(int k,int n)

       {     int i,found;

              i=found=0;

              While (!found&&i<n)

              {     i++;

                     if (a[i]&&b[k+i]&&c[n+k-i])

                     {     col[k]=i;

                            a[i]=b[k+i]=c[n+k-i]=0;

                            if (k==n) return 1;

                            else

                                   found=queen_one(k+1,n);

                            a[i]=b[k+i]=c[n+k-i]=1;

                     }

              }

              return found;

       }

六、贪婪法

       贪婪法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪婪法不要回溯。

       例如平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有各种发表方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。这就是在使用贪婪法。这种方法在这里总是最优,是因为银行对其发行的硬币种类和硬币面值的巧妙安排。如只有面值分别为1511单位的硬币,而希望找回总额为15单位的硬币。按贪婪算法,应找111单位面值的硬币和41单位面值的硬币,共找回5个硬币。但最优的解应是35单位面值的硬币。

【问题】       装箱问题

    问题描述:装箱问题可简述如下:设有编号为01、…、n-1n种物品,体积分别为v0v1、…、vn-1。将这n种物品装到容量都为V的若干箱子里。约定这n种物品的体积均不超过V,即对于0in,有0viV。不同的装箱方案所需要的箱子数目可能不同。装箱问题要求使装尽这n种物品的箱子数要少。

       若考察将n种物品的集合分划成n个或小于n个物品的所有子集,最优解就可以找到。但所有可能划分的总数太大。对适当大的n,找出所有可能的划分要花费的时间是无法承受的。为此,对装箱问题采用非常简单的近似算法,即贪婪法。该算法依次将物品放到它第一个能放进去的箱子中,该算法虽不能保证找到最优解,但还是能找到非常好的解。不失一般性,设n件物品的体积是按从大到小排好序的,即有v0v1≥…≥vn-1。如不满足上述要求,只要先对这n件物品按它们的体积从大到小排序,然后按排序结果对物品重新编号即可。装箱算法简单描述如下:

{     输入箱子的容积;

       输入物品种数n

       按体积从大到小顺序,输入各物品的体积;

       预置已用箱子链为空;

       预置已用箱子计数器box_count0

       for (i=0;i<n;i++)

       {     从已用的第一只箱子开始顺序寻找能放入物品i 的箱子j

              if (已用箱子都不能再放物品i

              {     另用一个箱子,并将物品i放入该箱子;

                     box_count++

              }

              else

                     将物品i放入箱子j

       }

}

       上述算法能求出需要的箱子数box_count,并能求出各箱子所装物品。下面的例子说明该算法不一定能找到最优解,设有6种物品,它们的体积分别为:604535202020单位体积,箱子的容积为100个单位体积。按上述算法计算,需三只箱子,各箱子所装物品分别为:第一只箱子装物品13;第二只箱子装物品245;第三只箱子装物品6。而最优解为两只箱子,分别装物品145236

       若每只箱子所装物品用链表来表示,链表首结点指针存于一个结构中,结构记录尚剩余的空间量和该箱子所装物品链表的首指针。另将全部箱子的信息也构成链表。以下是按以上算法编写的程序。

【程序】

# include <stdio.h>

# include <stdlib.h>

typedef  struct  ele

{     int  vno;

       struct  ele  *link;

}     ELE;

typedef  struct  hnode

{     int  remainder;

       ELE  *head;

       Struct  hnode  *next;

}     HNODE;

 

void  main()

{     int  n, i, box_count, box_volume, *a;

       HNODE  *box_h,  *box_t,  *j;

       ELE   *p,  *q;

       Printf(“输入箱子容积\n”);

       Scanf(“%d”,&box_volume);

       Printf(“输入物品种数\n”);

       Scanf(“%d”,&n);

       A=(int *)malloc(sizeof(int)*n);

       Printf(“请按体积从大到小顺序输入各物品的体积:”);

       For (i=0;i<n;i++)    scanf(“%d”,a+i);

       Box_h=box_t=NULL;

       Box_count=0;

       For (i=0;i<n;i++)

       {     p=(ELE *)malloc(sizeof(ELE));

              p->vno=i;

              for (j=box_h;j!=NULL;j=j->next)

                     if (j->remainder>=a[i])   break;

              if (j==NULL)

              {     j=(HNODE *)malloc(sizeof(HNODE));

                     j->remainder=box_volume-a[i];

                     j->head=NULL;

                     if (box_h==NULL)        box_h=box_t=j;

                     else  box_t=boix_t->next=j;

                     j->next=NULL;

                     box_count++;

              }

              else  j->remainder-=a[i];

              for (q=j->next;q!=NULL&&q->link!=NULL;q=q->link);

              if (q==NULL)

              {     p->link=j->head;

                     j->head=p;

              }

              else

              {     p->link=NULL;

                     q->link=p;

              }

       }

       printf(“共使用了%d只箱子box_count);

       printf(“各箱子装物品情况如下:”);

       for (j=box_h,i=1;j!=NULL;j=j->next,i++)

       {     printf(“%2d只箱子,还剩余容积%4d,所装物品有;\n”,I,j->remainder);

              for (p=j->head;p!=NULL;p=p->link)

                     printf(“%4d”,p->vno+1);

              printf(“\n”);

       }

}

 

上一页  [1] [2] [3] [4] [5] [6] 下一页

转帖于:计算机等级考试_考试吧
文章搜索  
看了本文的网友还看了:
计算机等级考试权威辅导教材: 订书电话:010-62168566  更多>>>
网友评论
昵 称: *  评 分: 1分 2分 3分 4分 5分
标题:   匿名发表    (共有条评论)查看全部评论>>
版权声明 -------------------------------------------------------------------------------------
  如果计算机等级考试网所转载内容不慎侵犯了您的权益,请与我们联系,我们将会及时处理。如转载本计算机等级考试网内容,请注明出处。
关于本站  网站声明  广告服务  联系方式  付款方式  站内导航  客服中心  友情链接  考试论坛  网站地图
Copyright © 2004-2008 考试吧计算机等级考试网 All Rights Reserved    
中国科学院研究生院权威支持(北京) 电 话:010-62168566 传 真:010-62192699
百度大联盟黄金认证  十佳网络教育机构  经营许可证号:京ICP060677