枚举:基于逐个尝试答案的一种问题求解策略
例如:求小于N的最大素数。枚举法:逐个判断N-1、N-2、N-3等是不是素数
例题:
一、完美立方
·形如a3=b3+c3+d3的等式被称为完美立方等式。例如12³=6³+8³+10³。编写一个程序,对任给的正整数N(N<=100),寻找所有的四元组(a,b,c,d),使得a³=b³+c³+d³,其中a,b,c,d大于1,小于等于N,且b<=c<=d。
·输入
一个正整数N(N<=100)
·输出
每行输出一个完美立方。输出格式为:
Cube=a,Triple=(b,c,d)
其中a,b,c,d所在位置分别用实际求出四元组值代入。
请按照a的值,从小到大依次输出。当两个完美立方等式中的a值相同,则b值小的优先输出、仍相同的则c值小的优先输出、再相同则d值小的优先输出。
·解题思路
四重循环枚举a,b,c,d,a在最外层,d在最里层,每一层都是从大到小枚举;
枚举范围a:[2,N] b:[2,a-1] c:[2,b-1] d:[2,c-1]
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int N;
scanf("%d\n",&N);
for(int a=2;a<=N;++a)
{
for(int b=2;b<a;++b)
{
for(int c=2;c<b;++c)
{
for(int d=2;d<c;++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);
}
}
}
}
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。
·输出
从给定日子起,下一次三个高峰同一天的日子的天数。
·解题思路
1、从第d+1天开始,一直试到第21252天,其中每个日期K,看是否满足。(k-p)%23==0&&(k-e)%28==0&&(k-i)%33==0
2、先判断k是否满足p,再判断在满足p的前提下是否满足e,再判断是否在满足p,e的前提下是否满足i,再筛选k是否小于等于21252。
#include<iostream>
#include<cstdio>
using namespace std;
#define N 21252
int main()
{
int p,e,i,d,caseNo=0;
while(cin>>p>>e>>i>>d&&p!=-1)
{
int k;
++caseNo;
for(k=d+1;(k-p)%23;++k)
for(;(k-e)%28;K+=23)
for(;(k-i)%33;k+=23*8)
cout<<"Case"<<caseNo<<":the next triple peak occurs in"<<k-d;
}
return 0;
}
三、称硬币
·有十二枚硬币。其中有11枚真币和1枚假币。假币和真币重量不同,但不知道假币比真币重还是轻。现在,用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是重还是轻(数据保证一定能找出来)。
·输入
1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even
·输出
K is the counterfeit coin and it is light.
·解题思路
先假设A是重的假币,代入结果,若符合则A为假币且重,否则假设A是轻的假币,代入结果,若符合则A为假币轻。若都不符合则换B进行,以此类推,直至测出假币。
#include<iostream>
#include<cstdio>
using namespace std;
char Left[3][7];
char Right[3][7];
char result[3][7];
bool IsFake(char c,bool light);
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;
}
}
}
return 0;
}
bool IsFake(char c,bool light){
for(int i=0;i<3;++i){
char *pLeft,*pRight;
if(light){pLeft=Left[i];pRight=Right[i];}
else{
pLeft=Right[i];
pRight=Left[i];
}
switch(result[i][0]){
case 'u':if(strchr(pRight,c)==NULL) return false;break;
case 'e':if(strchr(pLeft,c)||strchr(pRight,c)) return false;break;
case 'd':if(strche(pLeft,c)==NULL) return false;break;
}
}
return true;
}
bool IsFake(char c,bool light)
bool light,返回值为true则假设硬币为轻;false则假设硬币为重;bool IsFake,返回值为true则表示假设成立,否则不成立。
case 'u':if(strchr(pRight,c)==NULL) return false;
判断天平右边是否有假币,若有则返回false
case 'e':if(strchr(pLeft,c)||strchr(pRight,c)) return false;
天平是平的,但凡左右两边含假币,都会返回false。
case 'd':if(strchr(pLeft,c)==NULL) return false;
假币在天平左边,若不在左边,则返回false。
声明:switch语句按照假币为轻编写,若假设假币为重,则将最初的pLeft,pRight对调即可。
四、星星点灯(孩子要哭了)
·有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯,当按下一个按钮后,该按钮以及周围位置(上下左右)的灯都会改变状态。如果灯原来是点亮的,就会被熄灭,否则被点亮。在矩阵角上的按钮改变3盏灯的状态,边上改变4盏灯的状态,其它改变5盏灯的状态。一个操作会抵消另一种状态。要求怎样按使灯全部熄灭。
·输入
1
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
·输出
PUZZLE#1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
·解题思路
第一行确定按的类型后,第二行要使灯熄灭则根据第一行,按钮的方式固定,第三行由第二行按钮的方式固定,第四行由第三行固定,第五行由第四行固定,若第五行按了之后仍不能熄灭,则第一行按的方式错误。改变第一行按的方式,再次测试,直到第五行全部熄灭。
(即:找出代表全部的局部,然后枚举局部)
·采用位运算,一维char类型数组。每组char可存6个0或1
·枚举第一行,第一行有2的五次方,即64种状态。利用二进制位,一个二进制位可以表示0和1两种状态;两个二进制位可以表示00、01、10、11四种状态;三个二进制位可以表示000、001、010、011、100、101、111、110八种状态;以此类推,六个二进制位可以表示64种状态,每种状态对应类似于第一组灯的状态。
#include<stdio.h>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
char oriLights[5];//存储灯的矩阵
char lights[5];//变化灯的矩阵
char result[5];//最终结果
int GetBit(char c,int i)
{
return (c>>i)&1;
}
void SetBit(char &c,int i,int v)
{
if(v){
c|=(1<<i);
else
c&=~(1<<i);
}
void FlipBit(char &c,int i)
{
c^=(1<<i);
}
void OutputResult(int t,char result[])
{
cout<<"PUZZLE#"<<t<<endl;
for(int i=0;i<5;i++)
for(int j=0;j<6;j++){
cout<<GetBit(result[i],j);
if(j<5)
cout<<" ";
}
cout<<endl;
}
}
int main()
{
int T;
cin>>T;
for(int t=1;t<=T;++t)
{
for(int i=0;i<=5;++i)
for(int j=0;j<6;++j){
int s;
cin>>s;
SetBit(oriLights[i],j,s);
}
for(int n=0;n<64;++n)
{
int switchs=n;
memcpy(lights,oriLights,sizeof(oriLights));
for(int i=0;i<5;i++)
{
result[i]=switchs;
for(int j=0;j<6;j++)
{
if(GetBit(switchs,j)){
if(j>0) FlipBit(lights[i],j-1);
FlipBit(lights[i],j);
if(j<5) FlipBit(lights[i],j+1);
}
}
if(i<4)
lights[i+1]^=switchs;
switchs=lights[i];
}
if(lights[4]==0)
{
OutputResult(t,result);
break;
}
}
}
}
(代码还不太理解,照搬的)哭了哭了。。。。