poj 1753/2965 bfs+位运算(关灯游戏/开冰箱门)

题意:1753:关灯游戏,求使得画面全是同一个颜色为止的最小步数。

2965:仍然是4*4的方格,对某点的操作为对该点所在行和所在列全部翻转,问最小部数并输出方案。

思路:bfs+位运算。注意:棋盘一共有16个位置,每个位置最多翻转一次,所以搜索空间最大为2^16。每一种状态可以用一个数字表示。

2965:同前,队列里多记录一些信息即可。

1753代码:

#include <stdio.h>
#include <string.h>
char begin[5][5];
int q[1<<16],hash[1<<16];//hash标记下标状态是否被搜到过
int s;
int change(int pos,int x){
	int op = 0;
	if(x/4)//翻转处不在第一行
		op |= (1<<(19-x));
	if(x<12)//翻转处不在第四行
		op |= (1<<(11-x));
	if(x%4!=0)//翻转处不在最左列
		op |= (1<<(16-x));
	if(x%4!=3)//翻转处不在最右列
		op |= (1<<(14-x));
	op |= (1<<(15-x));
	return pos ^= op;
}
int bfs(){
	int i,front,rear;
	front = rear = -1;
	q[++rear] = s;
	while(front < rear){
		int pos = q[++front];
		for(i = 0;i<16;i++){//依次翻转16个位置
			int temp = change(pos,i);
			if(!temp || temp==65535)
				return hash[pos];
			if(!hash[temp]){
				hash[temp] = hash[pos]+1;
				q[++rear] = temp;
			}
		}
	}
	return 0;
}
int main(){
	int i,j;
	freopen("a.txt","r",stdin);
	memset(hash,0,sizeof(hash));
	for(i = 0;i<4;i++)
		scanf("%s",begin[i]);
	for(i = 0;i<4;i++)
		for(j = 0;j<4;j++){
			s <<= 1;
			if(begin[i][j] == 'b')
				s |= 1;
		}
	if(!s || s==65535)//一开始就是完好状态,特殊判断
		printf("0\n");
	else{
		hash[s] = 1;
		i = bfs();
		if(i)
			printf("%d\n",i);
		else
			printf("Impossible\n");
	}
	return 0;
}

2965代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
int state;
int flag[(1<<16)+5];
struct node{
    int x,y,d,p,t;
}q[(1<<16)+5];
int change(int s,int x){
    int i,j,op = 0;
    j = x/4;
    for(i = j*4;i<j*4+4;i++)    //每行
        op |= (1<<i);
    j = x%4;
    for(i = j;i<16;i+=4)        //每列
        op |= (1<<i);
    return s^op;                //进行翻转
}
int bfs(){
    int i,j,front,rear;
    struct node now;
    front = -1;
    rear = 0;
    while(front < rear){
        now = q[++front];
        if(now.t == (1<<16)-1)  //找到目标状态,即16位全部为1
            return front;
        for(i = 0;i<16;i++){
            j = change(now.t,i);//变换后的新状态
            if(!flag[j]){
                q[++rear].t = j;
                q[rear].x = i/4;
                q[rear].y = i%4;
                q[rear].p = front;
                q[rear].d = now.d+1;
                flag[j] = 1;
            }
        }
    }
    return -1;
}
int main(){
    int i,j;
    char ch;
    clc(flag, 0);
    state = 0;
    for(i = 0;i<4;i++){
        for(j = 0;j<4;j++){
            ch = getchar();
            if(ch == '-')
                state |= (1<<(i*4+j));
        }
        getchar();
    }
    q[0].d = 0;
    q[0].p = -1;
    q[0].t = state;
    flag[state] = 1;
    j = bfs();
    printf("%d\n",q[j].d);
    while(q[j].p!=-1){
        printf("%d %d\n",q[j].x+1,q[j].y+1);
        j = q[j].p;
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值