基于逐个尝试答案的一种问题求解策略,解决问题时最先想到的搜索方法。
题目:有12枚硬币。其中有11枚真币和1枚假币。假币和真币重量不同,但不知道假币比真币轻还是重。现在,用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是轻还是重。
输入:第一行是测试数据组每组数据有三行,每行表示一次称量的结果。硬币A-L。称量结果分为三部分:天平左边放置的硬币 天平右边放置的硬币 平衡状态(up、down、even右相对于左) 左右硬币数相同。
输出:输出哪一个标号的硬币是假,并说明轻还是重
解题思路:枚举每一枚硬币是轻/重,看是否符合称量结果。
注:strchr函数功能为在一个串中查找给定字符的第一个匹配之处。函数原型为:char strchr(const char str, int c),即在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。strchr函数包含在C 标准库 <string.h>中。
#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为真表示假设假币为轻,否则表示假币为重
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(strchr(pLeft,c)==NULL)
return false;
break;
}
}
}
题目:5*6的灯矩阵,输入状态(1代表开,0代表灭),输出开关方案(1代表按一次开关),开关按下后,四周的灯都会改变状态。
思路:每个状态都试一下,2^30次,肯定超时 。想办法缩小枚举范围!
考虑能否用枚举局部:局部确定,剩余部分确定。
枚举第一行,状态是2^6=64! -——>对应剩余行确定!(只有第二列才能改变第一列的灯,以此类推)
这里介绍一种非常好用的二进制枚举方法:枚举一个k位二进制数的每一位变化,只需要对应一个int型变量从0变到2^k-1进行枚举
即一行灯对应一个0-63的数字,对每一盏灯的操作即进行位运算操作
为了节省空间,采用char类型变量储存这个数字(只有8个比特)
技巧:异或的逻辑:跟0异或不变,跟1异或取反。
具体代码如下:
#include<iostream>
#include<string>
#include<cstring>
#include<memory>
using namespace std;
int GetBit(char c,int i){
//取c的第i位
return (c>>i) & 1;
}
void SetBit(char& c,int i,int v){
//设置c的第i位为v 用引用!
if(v)
c |= (1<<i);
else
c &= ~(1<<i);
}
void Flip(char& c,int i){
//将c的第i位取反 异或(跟0异或不变,跟1异或反转)
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(){
char oriLights[5]; //最初灯矩阵,一个比特表示一盏灯
char lights[5]; //不停变化的灯矩阵
char result[5]; //结果开关矩阵
char switchs; //某一行的开关状态
int T;
cin>>T;
for (int t=1;t<=T;++ t){
memset(oriLights,0,sizeof(oriLights));
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){//遍历首行开关的64种状态
memcpy(lights,oriLights,sizeof(oriLights));
switchs=n;//第i行的开关状态
for(int i=0;i<5;++i){
result[i]=switchs;//第i行的开关方案
for(int j=0;j<6;j++){
if(GetBit(switchs,j)){
if(j>0)
Flip(lights[i],j-1);//改左灯
Flip(lights[i],j);//改开关位置的灯
if(j<5)
Flip(lights[i],j+1);//改友灯
}
}
if(i<4)
lights[i+1] ^= switchs;//改下一行的灯! 用异或!!
switchs=lights[i]; //第i+1行开关方案和第i行灯情况相同
}
if(lights[4]==0){
outputResult(t,result);
break;
}
}
}
return 0;
}原文:https://www.cnblogs.com/wwk510/p/12483363.html