你来我们毒蛇帮总部干什么|

asdio

园龄:4年7个月粉丝:1关注:0

蛮力法

概述

蛮力法(brute force method,也称穷举法或枚举法),是一种简单直接地解决问题的方法,采用一定的策略依次处理待求解问题的所有元素,从而找出问题的解

蛮力法的关键

依次处理所有元素

  • 确定穷举的范围
  • 保证处理过的元素不再被处理

蛮力法的设计思想

  • 找出枚举范围
    • 分析问题所涉及的各种情况
  • 找出约束条件
    • 分析问题的解需要满足的条件,并用逻辑表达式表示

例题

百元买鸡

题目:已知公鸡 5 元一只,母鸡 3 元一只,小鸡 1 元三只,用 100 元钱买 100 只鸡,问公鸡、母鸡、小鸡各多少只

分析:

约束条件如下:x+y+z=1005x+3y+z/3=100,依次代数测试是否符合条件

值得注意的是,为了减少判断次数,添加约束条件:{0x200y330z100

int Chicken(){
    int x,y,z,count=0;
    for (x = 0; x < 20; x++){
        for ( y = 0; y < 33 ; y++){
            z = 100 - x - y;
            if (z%3 == 0 && z/3 + 5*x + 3*y == 100){
                count++;
                cout << "公鸡:" << x << "只,母鸡:" << y << "只,小鸡:" << z << "只" << endl;
            }
        }  
    }
    if (count == 0){
        cout << "没有符合条件的解" << endl;
    }
}

串匹配问题

问题:给定两个字符串 S 和 T,在主串 S 中查找子串 T 的过程称为串匹配(string matching,也称模式匹配),T 称为模式

分析

  • 朴素模式(BF算法)

    从S头开始匹配,若匹配失败,从S的第二位重新匹配,以此类推

    int BF(char s[],char t[]){
      int i=0,j=0;
      int index=0;
      while(s[i]!='\0'&&t[j]!='\0'){
          if(s[i]==t[j]){
              i++;
              j++;
          }
          else{
              i=++index;
              j=0;
          }
      }
      if(t[j]=='\0')
          return index;
      else
          return -1;
    }
    
  • KMP算法

    • 找出模式串的next数组

    next[j]={1,j=0max{k|1k<j,T[0]···T[k1]=T[jk]···T[j1]}//0,

    • 若相同继续比较,若不同j回溯到next[j]位置

    • j=-1,则i和j均++(j下标移动到0,保证数组下标不小于0)

      void getNext(char T[], int next[]){
          int i, j, len;
          next[0] = -1;
          // 依次求next[j]
          for (j = 1; T[j] != '\0'; j++){
              // 相等子串的最大长度为j-1
              for (len = j - 1; len >= 1; len--){
                  for (i = 0; i < len; i++)
                      if (T[i] != T[j - len + i])
                          break;
                  if (i == len){
                      next[j] = len;
                      break;
                  }
          }
          if (len < 1)
              next[j] = 0; // 其他情况,无相等子串
           }
      }
      // 求T在S中的序号
      int KMP(char S[], char T[]){
          int i = 0, j = 0, next[80];
          getNext(T, next);
          while (S[i] != '\0' && T[j] != '\0'){
              if (S[i] == T[j]){
                  i++;
                  j++;
              }
              else{
                  j = next[j];
                  if (j == -1){
                      i++;
                      j++;
                  }
              }
          }
          if (T[j] == '\0')
              return (i - j + 1); // 返回本趟匹配的开始位置
          else
              return 0;
      }
      

凸包问题

问题:凸包问题要求为平面上具有 n 个点的集合S构造最小凸多边形。
img

分析:连接图中的任意两点,若剩余点都在直线的一侧,则该线段是凸包边界上的一部分,运用蛮力法解决凸包问题,依次判断每个点到各个点的线段是否是边界的一部分。
为防止重复,只考虑 i<j 的点对。

int bulgePack(int x[],int y[],int n,int px[],int py[]){
    int sign1,sign2;
    int index=0;
    for (int i = 0; i < n-1; i++){
        for (int j = i+1; j < n; j++){
            sign1 = 0;
            sign2 = 0;
            //计算两点组成的线段方程
            int a = y[i]-y[j];
            int b = x[j]-x[i];
            int c = x[i]*y[j]-x[j]*y[i];
            int k;
            //判断剩余点是否在直线的同一侧
            for (k = i; k < n; k++){
                if(k!=i&&k!=j){
                    if(a*x[k]+b*y[k]+c>0){
                        sign1=1;
                    }else{
                        sign2=1;
                    }
                    if(sign1==1&&sign2==1){
                        break;
                    }   
                }   
            }
            if (k==n){
                px[index]=x[i];
                py[index++]=y[i];
                px[index]=x[j];
                py[index++]=y[j];
            }
        } 
    }
    return index;
}

练习

    • 问题:设计算法将一个给定的真分数化简为最简分数,例如将6/8化简为3/4
    • 实现
      int simplification(int x,int y,int &a,int &b){
          for (int i = 2; i <= x; i++){
              if (x % i == 0 && y % i == 0){
                  x /= i;
                  y /= i;
                  i = 1;
              }
          }
          a = x;
          b = y;
          return 0;
      }
      
    • 问题:判断大数能否被11整除
    • 分析:从右开始两两一组,判断和能否被11整除,如561245,判断56+12+45能否被整除
    • 实现:
      bool divByEleven(char n[]){
          int sum = 0;
          int i = 0;
          while(n[i] != '\0'){
              if(i % 2 == 0) sum += n[i] - '0';
              else sum += (n[i] - '0')*10;
              i++;
          }
          if(sum % 11 == 0) return true;
          return false;
      }
      
    • 问题:计算求解anmod m
    • 分析:取模之后再倍乘之后取模,结果一致
    • 实现:
      int mod(int a,int n,int m){
          int r=a;
          while(n>0){
              r%=m;
              r*=a;
              n--;
          }
          return r/a;
      }
      
    • 问题:删除重复的元素,要求移动次数较少
    • 分析:建立数组保存该元素是否出现过;设置索引值记录当前已经确定的数组位置
    • 实现
      int removeDuplicates(int* nums, int numsSize) {
          if (numsSize == 0) return 0;
          int hash[1001] = {0};
          int i = 0;
          for (int j = 0; j < numsSize; j++) {
              if (hash[nums[j]] == 0) {
                  hash[nums[j]] = 1;
                  nums[i++] = nums[j];
              }
          }
          return i;
      }
      
    • 问题:A[n],调整为左边全为奇数,右边全为偶数
    • 分析:类似快排的操作
    • 实现:
      void swap(int t[],int n){
          int i=0,j=n-1;
          while(i<j){
              if (t[i]%2==0) {
                  if (t[j]%2==1) {
                      int temp=t[i];
                      t[i]=t[j];
                      t[j]=temp;
                  }else{
                      j--;
                  }
              }else{
                  i++;
              }
          }
      }
      

本文作者:asdio

本文链接:https://www.cnblogs.com/agitm/p/17237140.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   asdio  阅读(737)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起