枚举——
一种基于逐个尝试的问题求解策略,重点在于减少不必要的遍历次数
例一 完美立方
∷形如a^3 =b3+c3+d^3的等式被称为完美立方等式。例如123= 6^3 + 8^3 + 10^3。编写一个程序,对任给的正整数N(N<100),寻找所有的四元组(a, b, c, d) ,使得a3=b3+ c^3+ d^3, 其中a, b, c, d大于1,小于等于N,且b<=c<=d。
∷输入一个正整数N (N≤100)。
∷每行输出一个完美立方,输出格式为:Cube = a, Triple = (b, c, d)其中a, b, c, d所在位置分别用实际求出四元组值代入。
#include<stdio.h>
// ++a和a++的作用都相当于a=a+1;但++a和a++不同之处在于++a是先执行a=a+1后,再使用的值;a++是先使用a的值后,在执行a=a+1。
int main()
{
int N;
scanf("%d",&N);
int a,b,c,d;
for(a=2;a<=N;++a)//a[2,n]
for(b=2;b<=a-1;++b)//b[2,a-1]
for(c=b;c<=a-1;++c)//c[b,a-1]
for(d=c;d<=a-1;++d)//d[c,a-1]
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);
return 0;
}
例二 生理周期
人有体力、情商、智商的高峰日子,它们分别每隔23天、28天和33天出现一次。对于每个人,我们想知道何时三个高峰落在同一天。给定三个高峰出现的日子p,e和i(不一定是第一次高峰出现的日子),再给定另一个指定的日子d,你的任务是输出日子d之后,下一次三个高峰落在同一天的日子(用距离d的天数表示)。例如:给定日子为10,下次出现三个高峰同一天的日子是12,则输出2。
∷输入四个整数:p, e, i和d。 p, e, i分别表示体力、情感和智力高峰出现的日子。d是给定的日子,可能小于p, e或 i。所有给定日子是非负的并且小于或等于365,所求的日子小于或等于21252。
∷输出
从给定日子起,下一次三个高峰同一天的日子(距离给定日子的天数)。
#include <stdio.h>
int main()
{
int p,e,i,d,caseNo = 0,k;
while(scanf("%d%d%d%d",&p,&e,&i,&d) &&p!=-1)
{
++caseNo;
for(k = d+1;(k-p)%23;k++); // 枚举体力高峰
while ((k-e)%28!=0) k+=23; // 枚举情感高峰
while ((k-i)%33!=0) k+=23*28; // 找到三高峰
printf("Case %d: the next triple peak occurs in %d days.\n",caseNo,k-d);
}
return 0;
}
例三 假币问题
有12枚硬币。其中有11枚真币和1枚假币。假币和真币重量不同,但不知道假币比真币轻还是重。现在,用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是轻是重(数据保证一定能找出来)。
∷输入
第一行是测试数据组数。每组数据有三行,每行表示一次称量的结果。银币标号为A-L。每次称量的结果用三个以空格隔开的字符串表示:天平左边放置的硬币 天平右边放置的硬币 平衡状态。其中平衡状态用up, down, 或 even表示, 分别为左端高、右端低和平衡。(天平左右的硬币数总是相等的)
∷输出哪一个标号的银币是假币,并说明它比真币轻还是重
解题思路:假设一个为假币,把它带入三次结果中,再判断结果是否成立。借助bool布尔变量,先假设假币为轻,在从全部硬币中一个一个枚举,若成立则真,若返回fault,则假币为重,并枚举出那个假币。
#include <iostream>
#include <cstring>
using namespace std;
char Left[3][7]; //天平左边硬币,三次称量
char Right[3][7]; //天平右边硬币
char result[3][7]; //结果
bool IsFake(char c,bool light) ;
//light 为真表示假设假币为轻,否则表示假设假币为重,c:假设那一枚硬币为假币
int main() {
//输入数据
int t;
cin >> t ;//数据组数
while(t--) {
for(int i = 0;i < 3; ++i) cin >> Left[i] >> Right[i] >> result[i];
//找假币
for(char c='A'; c<='L';c++)
{
if( IsFake(c,true) ){
cout << c << " is the counterfeit coin and it is light.\n";
break;
}
else if( IsFake(c,false) ){
cout << c << " is the counterfeit coin and it is heavy.\n";
break;
} } }
system("pause");
return 0; }
bool IsFake(char c,bool light) //若矛盾则假设错了
//light 为真表示假设假币C为轻,否则表示假设假币C为重
{
//情况一
for(int i = 0;i < 3; ++i) {
char * pLeft,*pRight; //指向天平两边的字符串
if(light)//假币为轻是真的
{
pLeft = Left[i];//左边第i次称量的集合,[i][a],第i次有a个元素
pRight = Right[i];
}
else {//如果假设假币是重的,则把称量结果左右对换。。。。???
pLeft = Right[i];
pRight = Left[i];
}
switch(result[i][0]) { //天平右边的情况,第i次称量结果是否矛盾
case 'u':
if ( strchr(pRight,c) == NULL)//右边轻,则假币要在右边 ,等于null,则与前面的话矛盾,返回false
return false;
break;//
case 'e':
if( strchr(pLeft,c) || strchr(pRight,c))//平衡,则如果在两边找到c,则矛盾
return false;
break;
case 'd':
if ( strchr(pLeft,c) == NULL)
return false;
break;
} }
//情况二
return true;/
}