算法:枚举

枚举:基于逐个尝试答案的一种问题求解策略

例如:求小于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;
}
}
}
}

(代码还不太理解,照搬的)哭了哭了。。。。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值