魔板(bfs)

魔板

题目描述

有这样一种魔板:它是一个长方形的面板,被划分成 n n n m m m 列的 n × m n \times m n×m 个方格。每个方格内有一个小灯泡,灯泡的状态有两种(亮或暗)。我们可以通过若干操作使魔板从一个状态改变为另一个状态。操作的方式有两种:

  1. 任选一行,改变该行中所有灯泡的状态,即亮的变暗、暗的变亮;

  2. 任选两列,交换其位置。

当然并不是任意的两种状态都可以通过若干操作来实现互相转化的。

你的任务就是根据给定两个魔板状态,判断两个状态能否互相转化。

输入格式

文件中包含多组数据。第一行一个整数 k k k,表示有 k k k 组数据。

每组数据的第一行两个整数 n n n m m m 0 < n , m ≤ 100 0 < n,m \leq 100 0<n,m100)。

以下的 n n n 行描述第一个魔板。每行有 m m m 个数字( 0 0 0 1 1 1),中间用空格分隔。若第 x x x 行的第 y y y个数字为 0 0 0,则表示魔板的第 x x x y y y 列的灯泡为“亮”;否则为“暗”。

然后的 n n n 行描述第二个魔板。数据格式同上。

任意两组数据间没有空行。

输出格式

k k k 行,依次描述每一组数据的结果。

若两个魔板可以相互转化,则输出 YES \texttt{YES} YES,否则输出 NO \texttt{NO} NO。(注意:请使用大写字母)

样例 #1

样例输入 #1

2
3 4
0 1 0 1
1 0 0 1
0 0 0 0
0 1 0 1
1 1 0 0
0 0 0 0
2 2
0 0
0 1
1 1
1 1

样例输出 #1

YES
NO

整体思路

对于题目中所提到的三种转换,采用三个函数来对应三种转换,但在广搜的过程中,我们需要进行判重,判重的目的是如果以前已经存在过这个状态,如经过一步a得到1 3 4 5 6 7 8 2,但是经过b,c两步也会得到1 3 4 5 6 7 8 2,那么此时经过b,c两部的这个状态就没有储存到队列里的需要,这边是判重的意义所在

ac代码

#include<bits/stdc++.h>
using namespace std;
struct mb{
	string xu;
	char xl[8];
};//xu存储着经过的操作,xl表示的则是当前的状态
mb first;
char en[10];
queue<mb> qu;
unordered_set<int> pc;//用于进行判重的set
mb A(mb t){
	mb a;
	a.xu=t.xu+"A";
	for (int i=0;i<8;i++)
	a.xl[i]=t.xl[7-i];
	return a;
}//A
mb B(mb t){
	mb b;b.xu=t.xu+"B";
	b.xl[0]=t.xl[3],b.xl[1]=t.xl[0];
	b.xl[2]=t.xl[1],b.xl[3]=t.xl[2];
	b.xl[4]=t.xl[5],b.xl[5]=t.xl[6];
	b.xl[6]=t.xl[7],b.xl[7]=t.xl[4];
	return b;
}//B
mb C(mb t){
	mb c;c.xu=t.xu+"C";
	for (int i=0;i<8;i++)
		c.xl[i]=t.xl[i];
	c.xl[1]=t.xl[6],c.xl[2]=t.xl[1];
	c.xl[5]=t.xl[2],c.xl[6]=t.xl[5];
	return c;
}//C
bool vis(mb t){
	int l;sscanf(t.xl,"%d",&l);//把t所对应的状态读入l
	if (pc.count(l)==0) {pc.emplace(l);return true;}//如果在pc中出现过l,那么count返回的是l,
	//如果没有出现过l,那么返回的是0,同时把l添加回去,返回true
	else return false;
}
bool check(mb t){
	for (char i=0;i<8;i++){
		if (t.xl[i]!=en[i]) return false;
	}
	return true;
}//查看有没有到达最终状态
void bfs(){
	while (!qu.empty()){//队列不为空,证明还有状态
		mb tmp,now=qu.front();qu.pop();//去队首状态并出队
		if (check(now)) {
			cout<<now.xu.size()<<endl<<now.xu;return;
		}//如果已经到达最终状态,输出答案
		tmp=A(now);if (vis(tmp)) qu.push(tmp);
		tmp=B(now);if (vis(tmp)) qu.push(tmp);
		tmp=C(now);if (vis(tmp)) qu.push(tmp);//进行abc三种操作,每种操作都判重一下,然后入队
	}
	return;
}
int main(){
	first.xu="";
	for (char i='1';i<'9';i++) first.xl[i-1-'0']=i;//存最初状态
	for (int i=0;i<8;i++){
		cin>>en[i];//输入最末状态
		getchar();//读取空格
	}
	qu.push(first);//添加进最初状态
	bfs();
	return 0;
}                                               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值