zoukankan      html  css  js  c++  java
  • 算法专题-暴力枚举篇

    Q1(uva 725):

      给出一个整数n,找到所有的0~9的排列,是的前五个数组成的整数能够整除后五个数组成的整数。

      分析:很典型的基本暴力枚举法,暴力求解往往伴随优化。这道题目的优化点在于枚举后五位得到10x9x8x7x6种情况,然后基于这些情况和等式关系,然后得到前面的整数,然后只需判断一下是否满足每个数字只出现了一次即可,由于题目是要求从小到大输出,这里枚举的时候控制一下从小到大枚举即可。

      参考代码如下:

     #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int main()
    {
    
    
        int i , j , k , m , n;
        int visit[10];
        int x;
        int cas = 0;
        while(scanf("%d",&x) && x)
      {
          if(cas++) {printf("
    ");}
          int ok = 0;
          int flag = 0;
        for(int i = 0;i <= 9;i++)
        {
    
               for(j = 0;j <= 9;j++)
               {
                     if(i == j)  continue;
                     for(k = 0;k <= 9;k++)
    
                     {
                         if(k == i || k == j) continue;
                         for(m = 0;m <= 9;m++)
                         {
                               if(m == i || m == j || m == k)  continue;
                               for(n = 0;n <= 9;n++)
                                 {
                                     memset(visit , 0 , sizeof(visit));
                                       if(n == i || n ==j || n == k || n == m) continue;
                                        int sum = 10000*i + 1000*j + 100*k + 10*m +n;
                                        if(x*sum >= 99999){flag = 1;break;}
                                        visit[i] = 1;visit[j] = 1;visit[k] = 1;visit[m] = 1;visit[n] = 1;
                                        int temp = x*sum;
                                        int nn = temp%10;temp/= 10;
                                        int mm = temp%10;temp/= 10;
                                        int kk = temp%10;temp/= 10;
                                        int jj = temp%10;temp/= 10;
                                        int ii = temp%10;
                                        visit[ii] = 1;visit[jj] = 1;visit[kk] = 1;visit[mm] = 1;visit[nn] = 1;
                                        int cnt = 0;
                                        for(int p = 0;p <= 9;p++)
                                               if(visit[p])  cnt++;
    
                                        if(cnt == 10)
                                             {printf("%d%d%d%d%d / %d%d%d%d%d = %d
    ",ii,jj,kk,mm,nn,i,j,k,m,n,x);ok=1;}
    
                                 }
                                 if(flag) break;
                         }
                         if(flag)  break;
                     }
                     if(flag) break;
               }
               if(flag)  break;
        }
        if(!ok)  printf("There are no solutions for %d.
    ",x);
    
    
      }
    }

      Q2(hdu 1422):

      顺序给出1,2,3…n个城市的生活费和花费,他们组成一个环123…n1,现在你只能顺时针游览,请问你最多游览多少个城市?

      分析:这道题目本质上还是暴力,但是伪装了一层优化的分析,容易想到枚举开始的城市,然后遍历n个位置维护一个最大值即可,但是这样是个O(n^2)的时间复杂度,考察这题的数据量n最大是100000,显然这个方法会超时。

      进一步思考,假设我们当前的状态是从i出发,走到了城市j,在游览j-1城市的时候还没有被赶回家,游览第j个城市被赶回去了,按照我们上面枚举的方法,下次的状态是从i-1出发。但是其中的技巧在于,第一种状态如果存在,i城市的净收入一定为正,因此从i-1城市出发,到达j城市的净收入必然为负,还是要被赶回家,因此下面要枚举的量应该是第j+1个城市,之前那个状态游览的城市为j-i+1,将其存起来,维护一个最大值即可。

      参考代码如下:

     #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 200000 + 5;
    int a[maxn];
    int main()
    {
         int n;
         while(scanf("%d",&n) != EOF)
         {
                for(int i = 1;i <= n;i++)
                {
                      int x , y;
                      scanf("%d%d",&x,&y);
                      a[i] = x - y;
                      a[n+i] = x - y;
                }
    
      //for(int i = 1;i <= n;i++) printf("%d ",a[i]);
                int num = 0;
                int Max = 0;
                int ans = 0;
                 for(int i = 1;i <= 2*n;i++)
                 {
                     ans += a[i];
                     if(ans >= 0)
                          num++;
                     else
                     {
                           Max = max(num , Max);
                           //printf("%d
    ",Max);
                           num = 0 , ans = 0;
                     }
    
                    Max = max(num , Max);
                     if(Max == n) break;
    
    
                 }
    
                 printf("%d
    ",Max);
         }
    }

     Q3(最大乘积):

      给出n个元素组成的序列(n∈[1,18]),每个元素的绝对值大小不超过10,找到一个连续子序列,是的子序列各元素的乘积是最大的,输出这个最大值,如果最大值为负数,那么认为0是问题的答案。

      分析:连续子序列有两个要素,即起点和终点,记为有序对(x,y),考察数据大小,数据量较小,因此直接枚举即可维护最大值即可,这里记录最大值的变量最大可以达到10^18,因此用long long储存。

     #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn = 20;
    
    int main()
    {
       int a[maxn];
         int n;
         int cas = 1;
         while(scanf("%d",&n) != EOF)
            {
                  long long Max = 0;
                  int ok = 0;
               for(int i = 0;i < n;i++)
                   scanf("%d",&a[i]);
    
              for(int i = 0;i < n;i++)
                   for(int j = i;j < n;j++)
                  {
                          long long num = 1;
    
                              for(int k = i;k <=j;k++)
                                  {num *= a[k];}
                     // printf("%d
    ",num);
    
                           if(num <= 0)   continue;
                           else           Max = max(Max , num);
                           // printf("%d%d
    ",i , j);
                  }
    
    
                          printf("Case #%d: The maximum product is %lld.
    
    ",cas++,Max);
    
            }
    }

      Q4(uva10976):

      输入正整数k,找到所有的整数对(x,y),满足x>y,且1/k = 1/x + 1/y.

      分析:这个题的点在于分分析出枚举对象的范围,等式有2个变元,我们枚举一个,容易利用等式关系求得另一个。这里利用不等关系x>y,容易推得1/k≤2/y,这样我们看到y的范围是[1,2k]。

      参考代码如下:

    #include<cstdio>
    using namespace std;
    
    
    int main()
    {
          int k;
          while(scanf("%d",&k) != EOF)
          {
              int cnt = 0;
    
                    for(int y = 1;y <= 2*k;y++)
                    {
                           if(y - k <= 0)  continue;
    
                           if((k*y%(y-k)) == 0)  cnt++;
                    }
                    printf("%d
    ",cnt);
    
                   for(int y = 1;y <= 2*k;y++)
                    {
                           if(y - k <= 0)  continue;
    
                           if((k*y%(y-k)) == 0)  {printf("1/%d = 1/%d + 1/%d
    ",k , k*y/(y-k) , y);}
                    }
          }
    }
  • 相关阅读:
    用Python实现多核心并行计算
    Sublime Text 中文乱码
    Python_pickle
    New blog
    git Bash常用命令
    用TTS实现文本转语音
    bc#54 div2
    用Python制作新浪微博爬虫
    hdu5000 背包dp
    mac下配置Qt for Android+iOS
  • 原文地址:https://www.cnblogs.com/rhythmic/p/5980017.html
Copyright © 2011-2022 走看看