首页 > 编程语言 > 详细

算法基础(一):枚举

时间:2020-03-14 13:17:38      阅读:44      评论:0      收藏:0      [点我收藏+]

枚举

基于逐个尝试答案的一种问题求解策略,解决问题时最先想到的搜索方法。

Problem1:假币问题

题目:有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;
        }
    }
}

Problem2: 熄灯问题 POJ 1222

题目: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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!