一、 枚举算法:在找不到数学公式可以直接正面由所知得结果时,逐个尝试答案的每一种可能的结果,并以所知的信息为条件进行判断当前枚举的可能答案是否真正为答案。
二、特点:记得切换思路方式,不再是正向地从所知直接求结果了,而是一个个地列举可能结果,然后判断是否符合正确答案的条件。
三、算法关键:明确枚举的对象有哪些
明确每个对象枚举的范围(用循环语句枚举所有可能)
明确条件判断(题目的所有条件有哪些,每个条件如果转成代码语句进行判断)(可以在循环头处设置,也可用if条件语句等设置)
例题总结:
1、完美立方
编写一个程序,对任给的正整数N (N≤100),寻找所有的四元组(a, b, c, d),使得a^3= b^3+ c^3+ d^3,其中a,b,c,d 大于 1, 小于等于N,且b<=c<=d。
分析:
枚举的范围:a,b,c,d都要枚举----用四层循环进行枚举
每层循环的起始条件和终止条件由“a,b,c,d 大于 1, 小于等于N,且b<=c<=d”来设置
用if条件语句判断是否满足“a^3= b^3+ c^3+ d^3”
for(int a=2;a<=n;a++) for(int b=2;b<a;b++) for(int c=b;c<a;c++) for(int d=c;d<a;d++) { if(a*a*a==b*b*b+c*c*c+d*d*d) { printf("Cube = %d, Triple = (%d,%d,%d)\n",a,b,c,d); break; } }
2、人的周期
据说人生来就有三个生理周期,分别为体力周期、感情周期和智力周期,它们的周期长度分别为23天、28天和33天。
对于每个周期,会给出从当前年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。
给定一个从当年第一天开始的天数,你的任务是输出从给定时间开始(不包括给定时间),下一次三个高峰落在同一天的时间(距给定时间的天数)。
例如:给定时间为10,下次出现三个高峰同一天的时间是12,则输出2(注意这里不是3)。
输入包含多组数据,每一组数据由四个整数组成,数据以-1 -1 -1 -1 结束。
对于每一行的四个整数p, e, i和d, 其中p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d是给定的时间,可能小于p, e或i。所有给定时间是非负的并且小于或等于365,所求的时间小于或等于21252。
分析:
所要枚举的对象就是----距给定时间的天数
枚举的范围:从1到21252(题目给定的)
枚举的条件:是否满足这一天都是三个周期的高峰
方法一:
while(scanf("%d%d%d%d",&p,&e,&i,&d),p!=-1) { for(int k=1;k<=21252;k++) { if((k+d-p)%23==0&&(k+d-e)%28==0&&(k+d-i)%33==0) { num++; printf("Case %d: the next triple peak occurs in %d days.\n",num,k); break; } } }
方法二:(优化代码)
可以不用每一个k都试。
while (scanf("%d%d%d%d", &p, &e, &i, &d), p != -1) { for (k = 1; k <= 21252 && (k + d - p) % 23 != 0; k++); for (; (k + d - e) % 28 != 0; k += 23); for (; (k + d - i) % 33 != 0; k += 28 * 23); num++; printf("Case %d: the next triple peak occurs in %d days.\n", num, k); }
注意:这种方法的每个for循环后面都加分号,因为我们只要输出第一次的高峰,若没有每次都分号,最后会输出所有的高峰重合时间! 还有条件里是!=0 ,理清楚
3、假币实验
输入有三行,每行表示一次称量的结果。林克事先将银币标号为A-L。
每次称量的结果用三个以空格隔开的字符串表示:
天平左边放置的硬币 天平右边放置的硬币 平衡状态。
其中平衡状态用``up'', ``down'', 或 ``even''表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的
输出哪一个标号的银币是假币,并说明它比真币轻还是重(heavy or light)。
分析:
枚举的对象:假设每一个金币都是假轻和假重
枚举的范围:从‘A’到‘L’
成立的条件:满足三个天平测量的结果
for(int i=0;i<3;i++) cin>>Left[i]>>Right[i]>>Result[i]; for(char icoin='A';icoin<='L';icoin++) if(isfeitcoin(icoin,true)) { cout<<icoin<<" is the counterfeit coin and it is light. "<<endl; break; } else if((isfeitcoin(icoin,false))) { cout<<icoin<<" is the counterfeit coin and it is heavy. "<<endl; break; }
bool isfeitcoin(char icoin,bool islight) { string c; c.push_back(icoin); for(int i=0;i<3;i++) { string l=Left[i]; string r=Right[i]; if(!islight) swap(l,r); switch(Result[i][0]) { case 'e': if(l.find(c)!=string::npos||r.find(c)!=string::npos) return false; break; case 'u': if(r.find(c)==string::npos) return false; break; case 'd': if(l.find(c)==string::npos) return false; break; } } return true; }
注意:1、有一些现成的string函数可以用
2、为了防止swap后全局left和right改变了 所以建了新的l和r
3、思路不难,但是string的相关用法实现要巩固