POJ1753 -- BFS和位运算

该题俩个考点,一个是BFS广度优先遍历,另外一个是通过位的运算。

 

一。位运算

1.将输入的“0001 1001 1011 1001”字符串转换为十进制数6585,在这里是通过将输入的‘0’或‘1’进行位的左移运算实现。

代码如下:

    for(i=0;i<4;i++){
        scanf("%s",str);
        for(j=0;j<4;j++){
            if(str[j]=='b'){  //黑色为1,白色为0,将输入的二进制转换为10进制。eg:0001 1001 1011 1001 转为6585
                firstNum += 1<<(4*i+j); //通过左移实现,二进制变成10进制
            }else{
                firstNum +=0<<(4*i+j);
            }

        }
    }

 

2.选定一个块,然后实现0变1,1变0的翻转。在这里是通过和1进行异或运算实现0变1,1变0。

代码如下:其中pos的取值是0-15

int flipChess(int number,int pos){// 翻转棋子,和1异或,则反转该值。 即实现0变1,1变0

    number = number^(1<<pos); //翻转选中的棋子
    int row = pos/4;  //行数
    int col = pos%4;  //列数
    if(row > 0){
        number = number^(1<<(pos-4));  //翻转上方的棋子,第0行不能翻转
    }
    if(row<3){
        number = number^(1<<(pos+4)); //翻转下方的棋子,第3行(最后一行)不能翻转
    }
    if(col>0){
        number = number^(1<<(pos-1)); //翻转左边的棋子,第0列不能翻转
    }
    if(col<3){
        number = number^(1<<(pos+1)); //翻转右边的棋子,第3列(最后一列)不能翻转
    }
    return number;   //返回翻转后的十进制数
}


二。BFS

1.在这里,我们自定了一个循环队列。相比链队列,循环队列是事先申请好空间即int value[MAX]。该数组存放的就是棋盘对应的十进制数。

广度搜索就是将当前的一个状态值放到循环队列的数组里进行保存。在这里的难点就是将这个棋盘转换为状态值(即十进制数),然后入队。

代码如下:

#define MAX 65535
typedef struct que{  //循环队列,事先初始化数组value,用于存放队列的数据
    int value[MAX];
    int front;
    int rear;
}que;

void initQue(que* q){  //初始化队列
    q->front =0;
    q->rear = 0;
}

int enQ(que* q , int v){  //入队
    if((q->rear+1)%MAX == q->front){  //队列已满
        return 0;
    }
    q->value[q->rear] = v;
    q->rear = (q->rear+1)%MAX;
    return 1;
}

int deQ(que* q){   //出队
    if(q->front == q->rear){  //队列为空 ,返回-1
        return -1;
    }
    int temp = q->value[q->front];
    q->front = (q->front+1)%MAX;
    return temp;
}


2. 相比DFS , BFS通常用于求解最短或者最少的问题。而DFS则是通常用于求解所有问题。

首先我们将输入的第一个棋盘6585放入队列,接下来依次翻转第0-15个棋子,并得到翻转后的棋盘值。

如果该棋盘是清一色棋盘(即棋盘值为0或者65535),返回所需要的次数。

不是清一色棋盘,加入该棋盘未被搜索过,那么入队,并将次数加一。

在这里,我们定义了一个step[MAX]数组,用于记录棋盘的十进制值是否被检查过以及它的检查次数。

int BFS(int number){  //搜索成功返回当前步骤数,否则返回0
    que* q = (que*)malloc(sizeof(que));
    initQue(q);
    int i=0;
    step[number]=0;
    enQ(q,number);
    while(q->front != q->rear){//队列不为空
        int data = deQ(q);
        for(i=0;i<16;i++){
            int temp=data;
            temp=flipChess(temp,i);
            if(temp== 0 || temp == 65535){  //搜索成功
                return step[data]+1;
            }else if(step[temp]==-1){         //当前值没有被搜索过,则入队
                enQ(q,temp);
                step[temp]=step[data]+1;
            }
        }

    }
    return 0 ; //搜索失败返回0
}


 

最后,我们来看一下全部代码:

#include <stdio.h>
#include <stdlib.h>

char str[5];

#define MAX 65535

int step[MAX];

typedef struct que{  //循环队列,事先初始化数组value,用于存放队列的数据
    int value[MAX];
    int front;
    int rear;
}que;

void initQue(que* q){  //初始化队列
    q->front =0;
    q->rear = 0;
}

int enQ(que* q , int v){  //入队
    if((q->rear+1)%MAX == q->front){  //队列已满
        return 0;
    }
    q->value[q->rear] = v;
    q->rear = (q->rear+1)%MAX;
    return 1;
}

int deQ(que* q){   //出队
    if(q->front == q->rear){  //队列为空 ,返回-1
        return -1;
    }
    int temp = q->value[q->front];
    q->front = (q->front+1)%MAX;
    return temp;
}

int flipChess(int number,int pos){// 翻转棋盘,和1异或,则反转该值。 即实现0变1,1变0

    number = number^(1<<pos); //翻转选中的值
    int row = pos/4;  //行数
    int col = pos%4;  //列数
    if(row > 0){
        number = number^(1<<(pos-4));  //翻转上方的棋盘,第0行不能翻转
    }
    if(row<3){
        number = number^(1<<(pos+4)); //翻转下方的棋盘,第3行(最后一行)不能翻转
    }
    if(col>0){
        number = number^(1<<(pos-1)); //翻转左边的棋盘,第0列不能翻转
    }
    if(col<3){
        number = number^(1<<(pos+1)); //翻转右边的棋盘,第3列(最后一列)不能翻转
    }
    return number;   //返回翻转后的十进制数
}

int BFS(int number){  //搜索成功返回当前步骤数,否则返回0
    que* q = (que*)malloc(sizeof(que));
    initQue(q);
    int i=0;
    step[number]=0;
    enQ(q,number);
    while(q->front != q->rear){//队列不为空
        int data = deQ(q);
        for(i=0;i<16;i++){
            int temp=data;
            temp=flipChess(temp,i);
            if(temp== 0 || temp == 65535){  //搜索成功
                return step[data]+1;
            }else if(step[temp]==-1){         //当前值没有被搜索过,则入队
                enQ(q,temp);
                step[temp]=step[data]+1;
            }
        }

    }
    return 0 ; //搜索失败返回0
}

int main()
{
    int i =0,j=0;
    int firstNum =0;
    int result=0;
    memset(step,-1,sizeof(step));
    //freopen("input.txt","r",stdin);

    for(i=0;i<4;i++){
        scanf("%s",str);
        for(j=0;j<4;j++){
            if(str[j]=='b'){  //黑色为1,白色为0,将输入的二进制转换为10进制。eg:0001 1001 1011 1001 转为6585
                firstNum += 1<<(4*i+j); //通过左移实现,二进制变成10进制
            }else{
                firstNum +=0<<(4*i+j);
            }

        }
    }
    if(firstNum == 0 || firstNum == 65535){  //如果输入的是清一色棋盘,那么十进制数是0或者65535,所以输出0
        printf("0\n");
        return 0;
    }
    result =BFS(firstNum);
    if(result){
        printf("%d\n",result);
    }else{
       printf("Impossible\n");
    }

    return 0;
}


 


int flipChess(int number,int pos){// 翻转棋盘,和1异或,则反转该值。 即实现0变1,1变0

    number = number^(1<<pos); //翻转选中的值
    int row = pos/4;  //行数
    int col = pos%4;  //列数
    if(row > 0){
        number = number^(1<<(pos-4));  //翻转上方的棋盘,第0行不能翻转
    }
    if(row<3){
        number = number^(1<<(pos+4)); //翻转下方的棋盘,第3行(最后一行)不能翻转
    }
    if(col>0){
        number = number^(1<<(pos-1)); //翻转左边的棋盘,第0列不能翻转
    }
    if(col<3){
        number = number^(1<<(pos+1)); //翻转右边的棋盘,第3列(最后一列)不能翻转
    }
    return number;   //返回翻转后的十进制数
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值