zoukankan      html  css  js  c++  java
  • 抽签问题的思考(二分算法)

    问题:
    将写有数字的N个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片上的数字后都将其放回口袋中.如果这4个数字的和是M,就是你赢,否则就是你的朋友赢.

    很容易就可以写出下边的代码:

     1 for(int a=0; a<n; a++){
     2     for(int b=0; b<n; b++){
     3         for(int c=0; c<n; c++){
     4             for(int d=0; d<n; d++){
     5                 if(k[a] + k[b] + k[c] + k[d]==m){
     6                     f = true;
     7                 }
     8             }
     9         }
    10     }
    11 }

    上面是最初所记载的程序的循环部分.最内侧关于d的循环所做的事就是:

         检查是否有d使得Ka+Kb+Kc+Kd=M

    通过对式子移向,就能得到另一种表达方式:

         检查是否有d使得Ka=M-Kb+Kc+Kd

    就是检查数组K中所有元素,判断是否有M-Kb+Kc+Kd.

    这样的快速查找,就要用到二分搜索的算法.

    1.二分搜索与O(n3logn)

    排序O(nlogn)时间

    循环O(n3logn)时间

     1 int n,m,k[MAX];
     2 
     3 bool binary_search(int x){
     4     //x的存在范围是k[l],k[l+l]...k[r-l]
     5     int l=0,r=n;
     6     //反复操作直到存在范围为空
     7     while(r-l>=l){
     8         int i=(l+r)/2;
     9         if(k[i]==x) return true;//找到x
    10         else if(k[i]<x)   l=i+1;
    11         else r=i;
    12     }
    13     //没找到x
    14     return false;
    15 }
    16 
    17 viod solve(){
    18     //为了找到二分查找需要先排序
    19     sort(k,k+n);
    20 
    21     bool f=false;
    22     for(int a=0; a<n; a++){
    23         for(int b=0; b<n; b++){
    24             for(int c=0;c<n; c++){
    25                 //将最内则的循环替换成二分查找
    26                 if(binary_search(m-k[a]-k[b]-k[c])){
    27                     f=true;
    28                 }
    29             }
    30         }
    31     }
    32     if(f)   puts("Yes");
    33     else   puts("No");
    34 }

    排序O(n2logn)时间

    循环O(n2logn)时间

     1 int n,m,k[MAX];
     2 int kk[MAX*MAX];
     3 
     4 bool binary_search(int x){
     5     //x的存在范围是kk[l],kk[l+l]...kk[r-l]
     6     int l=0,r=n*n;
     7     //反复操作直到存在范围为空
     8     while(r-l>=l){
     9         int i=(l+r)/2;
    10         if(kk[i]==x) return true;//找到x
    11         else if(kk[i]<x)   l=i+1;
    12         else r=i;
    13     }
    14     //没找到x
    15     return false;
    16 }
    17 
    18 viod solve(){
    19     //枚举k[c]+k[d]的和
    20     for(int c=0; c<n; c++){
    21         for(int d=0; d<n; d++){
    22             kk[c*n+d]=k[c]+k[d];
    23         }
    24     }
    25     //排序以便进行二分搜索
    26     sort(kk,kk+n*n);
    27 
    28     bool f=false;
    29     for(int a=0; a<n; a++){
    30         for(int b=0; b<n; b++){
    31             //将内则的两个循环替换成二分搜索
    32             if(binary_search(m-k[a]-k[b])){
    33                 f=true;
    34             }
    35         }
    36     }
    37     if(f)   puts("Yes");
    38     else   puts("No");
    39 }

    本问题既需要二分搜索这一基础算法知识,也需要将四个数分成两两考虑的想象力.像这样从复杂度较高的算法出发,不断降低复杂度知道满足问题要求的过程,也是设计算法时常会经历的过程.

    <<挑战程序设计竞赛>>读后感

  • 相关阅读:
    hdu1814 Peaceful Commission 2-SAT
    上传下载文件
    文件下载类
    文件操作类
    MD5加密帮助类
    加密解密类
    发送邮件函数
    DataTable 分页
    服务器缓存帮助类
    Cookie帮助类
  • 原文地址:https://www.cnblogs.com/wangmengmeng/p/5221788.html
Copyright © 2011-2022 走看看