穷举法典例


穷举法也叫暴力搜索法,也就是遍历所有的情况,找出符合要求的组合,我给大家总结了三个相关例题:
一、八皇后问题
问题描述:八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上,请找出有多少种。2方法

1、算法分析:
(1)我们通过定义八个变量八重循环来模拟棋盘存放八皇后的合适位置,每个变量表示一行里存放皇后的合适列的位置,所以这个变量可以在棋盘的这个行上移动,长度范围限制为8,因为棋盘是8列的,也因为,我们每行就定义了一个变量代表一个皇后,所以行里面不存在同时有两个皇后的问题。
(2)其次,每列不能有两个皇后,竖线上不重复的情况相对简单,相信大家都能想到,假如我们设定两个坐标为(i,j)和(k,s),(i,j)代表在前面行的坐标,(k,s)代表在下面列的坐标,那么不在同一竖线上,可以表示为i!=k;
(3)在斜线上的话有四个方向,但是由于我们是从上往下摆放皇后的,所以每次摆放这行的皇后时,下一行还没有东西,所以只需要考虑上面两个斜线的方向,很形象的就是“米”字的上半部分的。大家可以想象一下二维坐标,(0,0)和(1,1)是不是在45度斜线上,(2,2)和(4,4,)是不是在同一个斜线上,这就是说明说明,如果两个坐标的横坐标的差等于纵坐标的差就是在同一斜线上,也就是i-k=j-s或者是k-i=s-j;这个是不是可以合并一下用绝对值表示,abs(i-k)=abs(s-k);

2、代码实现
//穷举法
#include
#include
//i1--i8存储每一行每个皇后可以摆放的列数
//判断条件i#==i#和abs(i#-i#)==#就是模拟的同一列和两个斜线的情况
void queen()
{
 int count=0;
 for(int i1=1;i1<=8;i1++)
    for(int i2=1;i2<=8;i2++)
    {
   if((i2==i1)||(abs(i1-i2)==1))
           {
   continue;}
   for(int i3=1;i3<=8;i3++)
   {
    if((i3==i2)||(abs(i3-i2)==1)||(i3==i1)||(abs(i3-i1)==2))
    {
    continue;}
    for(int i4=1;i4<=8;i4++)
    {
     if((i3==i4)||(abs(i3-i4)==1)||
      (i1==i4)||(abs(i1-i4)==3)||
     (i2==i4)||(abs(i2-i4)==2))
     {
    continue;}
     for(int i5=1;i5<=8;i5++)
     {
      if((i5==i4)||(abs(i5-i4)==1)||
      (i3==i5)||(abs(i3-i5)==2)||
      (i1==i5)||(abs(i1-i5)==4)||
          (i2==i5)||(abs(i2-i5)==3))
      {
    continue;}
      for(int i6=1;i6<=8;i6++)
      {
       if((i6==i5)||(abs(i6-i5)==1)||
       (i6==i4)||(abs(i6-i4)==2)||
          (i3==i6)||(abs(i3-i6)==3)||
          (i1==i6)||(abs(i1-i6)==5)||
             (i2==i6)||(abs(i2-i6)==4))
       {
    continue;}
       for(int i7=1;i7<=8;i7++)
       {
        if((i6==i7)||(abs(i7-i6)==1)||
        (i7==i5)||(abs(i7-i5)==2)||
           (i7==i4)||(abs(i7-i4)==3)||
              (i3==i7)||(abs(i3-i7)==4)||
              (i1==i7)||(abs(i1-i7)==6)||
                 (i2==i7)||(abs(i2-i7)==5))
        {
    continue;}
        for(int i8=1;i8<=8;i8++)
        {
         if((i8==i7)||(abs(i8-i7)==1)||
         (i6==i8)||(abs(i8-i6)==2)||
            (i8==i5)||(abs(i8-i5)==3)||
               (i8==i4)||(abs(i8-i4)==4)||
                  (i3==i8)||(abs(i3-i8)==5)||
                  (i1==i8)||(abs(i1-i8)==7)||
                     (i2==i8)||(abs(i2-i8)==6))
         {
         continue;}
         
         count++;
         printf("1:%d,2:%d,3:%d,4:%d,5:%d,6:%d,7:%d,8:%d,%d\n",i1,i2,i3,i4,i5,i6,i7,i8,count);
        }
       }
      }
     }
    }
   }
    }
}
int main()
{
 queen();
 return 0;
}

二、找零问题
问题描述:有人要找零,如果15分,23分,29分,41分,67分都有足够多,则凑成1808分有多少种情况
算法分析:
1、因为有五种零钱,所以我们定义五个变量模拟每种零钱找的数目;
2、每个零钱最少可以找0个,肯定不可能是负数,所以每个变量最少是从零开始,但是要凑齐一个找零数,也许都用一种钱币就可以完成找零,所以每种零钱个数的上限是需要找的总的1080的数目除以它的面值,只需要取整就行,因为如果有余数说明光凭这个币值完成不了找零,加一会多,无意义;
3、遍历所有情况时,我们可以做一些排除,比如如果当前的面值加起来已经大于1080了,那就不需要往下遍历了,因为肯定不符合,所以我们可以用continue结束本次循环,继续下次的。

代码实现:
int Money()
{
 int count = 0;
 for(int m1 = 0;m1<=1808/15;m1++)
 {
  for(int m2=0;m2<=1808/23;m2++)
  {
   if(m1*15+m2*23>1808)//将已经不符合情况的筛选出去。
   {
    continue;//结束本趟循环直接进入下一趟。    break:跳出一层循环。
   }
   for(int m3=0;m3<=1808/29;m3++)
   {
    if(m1*15+m2*23 + m3*29>1808)
    {
     continue;
    }
    for(int m4=0;m4<=1808/41;m4++)
    {
     if(m1*15+m2*23 + m3*29 + m4*41>1808)
     {
      continue;
     }
     for(int m5=0;m5<=1808/67;m5++)
     {
      if(m1*15+m2*23 + m3*29 + m4*41 + m5*67 == 1808)
      {
       count++;
       printf("15:%d,23:%d,29:%d,41:%d,67:%d\n",m1,m2,m3,m4,m5);
      }
     }
    }
   }
  }
 }
 return count;
}

三、对手匹配
问题描述:有两个乒乓球队,一个队有成员a,b,c,一个队有队员x,y,z,a不和x打,c不和x,z打,找出三对赛手名单。
算法分析
       这个题目的实现很简单只需要三重循环,把第一队的每个队员都和二队的队友遍历一遍,把不符合条件的情况剔除就行了。

代码实现:
int main()
{
 printf("%d\n",Money());
}*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值