枚举例题练习

注意怎么尽可能减少枚举的个数和范围

例题一:生理周期

 

 

 

 

 

 

 

 

解题思路:这题还是比较简单的,很容易就可以想到用枚举的方式解题,条件其实就是枚举每一天,看看距离所给高峰的距离能不能同时%23 28 33 ==0就好了。但是如果这样设计的话很明显就要用3重循环时间复杂度很高,如果给的数据很大的话很有可能会溢出,所以选择要想一个办法把枚举的个数或者是范围降低。那怎么办呢?

 

                 答案是:跳着找。因为每两个周期之间还要枚举相应的间隔,这个间隔是完全没必要枚举的,所以优化的思路就是先找到比如说第一个体力巅峰的位置,然后跳着周期找,因为要同时满足情商周期的同时也是体力周期,直到找到了一个两个周期重叠的位置,后面尝试的时候只要尝试既是体力高峰又是情商高峰的日子就好了。双高峰的日子出现的间隔很明显就是两者的最小公倍数。所以现在跳着他俩的最小公倍数去找与第三个高峰重叠的日子。

 

代码:

 

 

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int main() {
 5     int p, e, i, d, caseNo = 0;
 6     while (cin >> p >> e >> i >> d && p != -1) {//这种输入还是要学一下的
 7         caseNo++;
 8         int k;//这个就是天数
 9         for (k = d + 1; (k - p) % 23; ++k);
10         for (; (k - e) % 28; k += 23);
11         for (; (k - i) % 23; k += 23 * 28);
12         //这种for循环的使用注意一下,不要被以前的for死板循环的使用个禁锢住了
13         cout << "Case " << caseNo << ": the next triple peak occurs in " << k - d <<endl;
14     }
15     return 0;
16 }

 

 

总结:

  这题就是告诉我们可以通过循环的设计减少枚举的次数。还有一些写代码怎么写的技巧。

 

 

例题2:称硬币(poj 1013):

题目链接:http://poj.org/problem?id=1013

 

 

题目大意:

 

 

 

 

 

 

 解题思路:肯定是枚举咯!那要怎么枚举呢?就是枚举天平两边每一枚硬币分别是重和轻的情况。没每一枚硬币假设是轻的看看假设天平情况与题目中是否符合,若不符合再假设天平为重是否符合条件。其实我觉得这个枚举是相对不明显,不容易想到的。

代码:

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 char left[3][7];
 5 char right[3][7];
 6 char result[3][7];
 7 bool IsFake(char c, bool light) {
 8     for(int i = 0;i<3;i++){
 9         char *pleft *pright;
10         if(light){
11             pleft = left[i];
12             pright = left[i];
13         }else{
14             pleft = right[i];
15             pright = left[i];
16         }
17         switch(result[i][0]){
18             case 'u':
19                 if(strchr(pright,c)==NULL)
20                     return false;
21                 break;
22             case 'e':
23                 if(strchr(pleft,c)||strchr(pright,c))
24                     return false;
25                 break;
26             case 'd':
27                 if(strchr(pleft,c) == NULL)
28                     return false;
29                 break; 
30         }
31         return true;
32     }
33     
34 }
35 int main() {
36     int t;
37     cin >> t;
38     while (t--) {
39         for (int i = 0; i < 3; i++)
40             cin >> left[i] >> right[i] >> result[i];
41         for(char c = 'A';c<='L';c++){
42             if(IsFake(c,true)){
43                 cout<<c<<"is the counterfeit coid and it is light.\n";
44                 break;
45             }
46             if(IsFake(c,false)){
47                 cout<<c<<"is the counterfeit coid and it is height.\n";
48                 break;
49             }
50         } 
51     }
52     return 0;
53 }

 

 

 

 

代码的解释与总结: 首先就是数据的储存,总共就三种的数据,所以这个地方用了二维数组来储存天平两边的硬币(左右两边硬币数相等且从A到L)和结果(即天平右边是高还是平还是低),注意这个地方是以天平右边的高低来判断轻的硬币在什么位置。首先是case数的循环,里面就是对于三个例子的循环,最里面就是对每个硬币的循环,每个循环内部是对每一个硬币的轻还是重进行枚举。这里对轻重的判断放在了一个函数里面。这个IsFake有两个参数,第一个参数就是需要判断的硬币,第二个bool型的参数是判断是不是light。

                                           函数的循环内部设计了两个指针分别指向天平的左端和右段,这里如果是重的话,交换位置把左指针指向右边,右指针指向左边这样就可以不需要写两边判断。如果是左边高的话,且硬币是轻的,说明轻的硬币在左边,strchr是用来判断字符是不是在字符串内,这里就是判断硬币在不在左边。如果是相等的说明硬币不能在左边或者是右边。如果右边低说明硬币在左边。如果是重的话这些情况交换,这也是为什么在前面写上交换的原因。

                    

 

 

 

 

 

 

posted @ 2022-01-28 11:34  prize  阅读(63)  评论(0编辑  收藏  举报