枚举例题练习
注意怎么尽可能减少枚举的个数和范围
例题一:生理周期
解题思路:这题还是比较简单的,很容易就可以想到用枚举的方式解题,条件其实就是枚举每一天,看看距离所给高峰的距离能不能同时%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是用来判断字符是不是在字符串内,这里就是判断硬币在不在左边。如果是相等的说明硬币不能在左边或者是右边。如果右边低说明硬币在左边。如果是重的话这些情况交换,这也是为什么在前面写上交换的原因。