蛮力法策略--枚举

来源:互联网 发布:古代吃人 知乎 编辑:程序博客网 时间:2024/06/16 04:36

蛮力法

蛮力法是利用计算机运行速度快这一个特性。把问题所有的情况或所有的过程交给计算机逐一尝试,从中找出问题的解。

策略:枚举(穷举)

根据问题的条件将可能的情况一 一列举起来,逐一尝试找出问题的解。有时问题的规模太大,可以排除一些明显不合理的情况。
枚举法的一般规律:

找出枚举范围:分析问题所涉及的所有情况。找出约束条件:分析问题的解需要满足的条件,并用逻辑表达式解释。对枚举法的优化主要是对约束范围和约束条件的数学优化。

百钱百鸡

问题:

我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?

分析:

隐含约束条件:Z%3 = 0,因为鸡肯定是整只的(肯德鸡除外)。所以鸡仔的个数是3的倍数。

算法:

注意:计算机中遇到除法要小心!

/*    Name:     Copyright:     Author:     Date: 20/12/17 17:26    Description:     百钱百鸡问题 */#include <stdio.h>#include <stdlib.h>void Two(){    int x,y;    //枚举次数2000/3     for(x=0;x<100/5;x++){//约束范围         for(y=0;y<100/3;y++){//约束范围              if(x*5+y*3+(100-x-y)/3==100&&(100-x-y)%3==0){//约束条件                 printf("%d%d%d雏\n",x,y,100-x-y);            }        }    }    printf("-----\n");} int main(){    Two();//约束范围的变化可以大大提高效率,精简约束条件     int x,y,z;    //枚举次数是20万次     for(x=0;x<=100/5;x++){//约束范围         for(y=0;y<=100/3;y++){//约束范围             for(z=0;z<100*3;z++){//约束范围                 if(x+y+z==100&&x*5+y*3+z/3==100&&z%3==0){//约束条件                     printf("%d%d%d雏\n",x,y,z);                }            }        }    }    system("pause");    return 0;} 

百钱百鸡的数学优化

算式迷问题

问题:

    解算式迷:    A B C A B X          A --------------  D D D D D D 

分析:

不同的枚举对象,算法的效率不一样。

算法:

/*    Name:     Copyright:     Author:     Date: 20/12/17 18:06    Description:     解算式迷:    A B C A B X          A --------------  D D D D D D */#include <stdlib.h>#include <stdio.h>//选择不同的枚举对象,算法效率有显著的差别,枚举对象可以从各个角度去考虑 void Two(){    //63次枚举     int D,A;    for(D=1;D<=9;D++){        for(A=3;A<=9;A++){            long e = D*100000+D*10000+D*1000+D*100+D*10+D;             if(e%A==0){                long F = e/A;                if(F/10000==A&&(F/10)%10==A&&F%10==(F/1000)%10){                    printf("A:%d B:%d C:%d D:%d\n",A,F%10,F/100%10,D);                }            }        }    } } int main(){    Two();    int A,B,C,D;    //枚举次数700     for(A=3;A<=9;A++){//枚举范围         for(B=0;B<=9;B++){//枚举范围             for(C=0;C<=9;C++){//枚举范围             //约束条件的判断                 long temp = A*10000+B*1000+C*100+A*10+B;                long e = temp*A;                 int x = e%10;                e = e/10;                int i=0;                 for(i=1;i<=5;i++){                    int m = e%10;                    e = e/10;                    if(m!=x) break;                }                if(i==6){                    D = x;                    printf("A:%d B:%d C:%d D:%d\n",A,B,C,D);                }            }        }    }    system("pause");    return 0;} 

暴力最小公倍数

问题:

求出三分二数字的最小公倍数。

分析:

最小公倍数的定义是:一个整数的所有倍数中最小的一个。在问题规模很小的时候,可以选择三个数中最大的枚举其倍数,判断是否是其他两个数的倍数,最小的一个就是三个数的最小公倍数。

算法:

/*    Name:     Copyright:     Author:     Date: 20/12/17 19:03    Description:     暴力枚举三个数的最小公倍数 */#include <stdio.h>#include <stdlib.h>int main(){    int a,b,c;    scanf("%d %d %d",&a,&b,&c);     for(int i=1;;i++){        if(a*i%b==0&&a*i%c==0){            printf("%d %d %d这三个数的最小公倍数是:%d\n",a,b,c,a*i);break;        }    }     system("pause");    return 0;} 

狱史问题

问题:

某国王对囚犯进行大赦,让一狱吏n次通过一排锁着的n间牢房,每通过一次,按所定规则转动n间牢房中的某些门锁, 每转动一次, 原来锁着的被打开, 原来打开的被锁上;通过n次后,门锁开着的,牢房中的犯人放出,否则犯人不得获释。
转动门锁的规则是这样的,第一次通过牢房,要转动每一把门锁,即把全部锁打开;第二次通过牢房时,从第二间开始转动,每隔一间转动一次;第k次通过牢房,从第k间开始转动,每隔k-1 间转动一次;问通过n次后,哪些牢房的锁仍然是打开的?
输入
狱吏通过牢房的次数n和牢房的间数n(n<=32767)。
输出:被释放的犯人的房间号

分析:

题目中锁的状态只有两个:开 关,可以用一维数组来模拟锁的状态。
使用数学运算模拟开关锁:a[i] = 1-a[i]
枚举问题中所有的过程,最终的状态就是问题的解。

算法:

/*    Name:     Copyright:     Author:     Date: 20/12/17 19:03    Description:     狱史问题 */#include <stdio.h>#include <stdlib.h>int main(){    int n;     scanf("%d",&n);    int *a;    a = (int *)malloc(sizeof(int)*(n));     for(int i=0;i<n;i++){        a[i] = 1;    }    //把所有可能的过程枚举出来    for(int i=1;i<=n;i++){        for(int j=i-1;j<n;j = j+i){            a[j] = 1-a[j];        }    }    for(int i=0;i<n;i++){        if(a[i]==0){            printf("%d号监狱释放!\n",i+1);        }    }    system("pause");    return 0;} 
原创粉丝点击