[2019 ICPC Taipei-Hsinchu] A.Rush Hour Puzzle //bfs

题目链接

题意:在一个 6×6 的网格中,有一些车。车用一个长方形表示,满足只 有宽或长为 1。若宽为 1,则车左右移动,否则上下移动。 每辆车移动过程中不能有某个部分出现在另一辆车上。 在第 3 行第 6 列格子的右边有一个缺口,其他地方没有缺口。 除了 1 号车外,其他车子不能移出网格外。1 号车也只能从缺口处移出网格。 某个车每走一格算做一步。 问将 1 号车从缺口处移走的最少步数(车身完全移走),若步数 ≤ 10,则输出最小步数, 否则输出 −1。

思路://写过的最长的bfs,当然要记录一下 [汗.jpg]
没有技巧,就是硬bfs,用重载node的set记录状态是否到达过。


方法就是从初始状态开始进行bfs,每次扩展出来一个新状态(即让某一辆车移动一步),比较麻烦的点在于记录状态和判重。
这个题的每个状态应该是一个矩阵,代表这个状态的停车场分布。所以建一个struct存状态。
然后扩展新状态,就是枚举每辆车,使其上下/左右移动一步,若这个状态没出现过,就入队。
判重应该可以用hash或者set,我hash不太熟练,所以就用了set(重载一下"<“和”==")
然后我程序里,用了cars记录的每辆车的位置和状态(水平or竖直),为了方便移动车子。 node是用来存每个状态。


变量说明:
cars中,len是车子长度、u记录车子在同一列还是是同一行、pos存车子所在的列/行、s和t记录车头车尾的位置。
node中,step是使用的步数、v[20]存每个车子现在的位置、a存停车场矩阵
(好像要素有点多,如果有更容易的写法当然更好)

#include<bits/stdc++.h>
using namespace std;
int a_[7][7],ans=11,cnt=1,c,sum;
struct cars{
	int len;
	int u,pos,s,t;  //u=1行,u=0列 
	cars(){u=-1;s=7;}
}v[20];
struct node{
	int step;
	cars v[20];
	int a[7][7];
	int c;
	node(){
		for(int i=0;i<=6;i++)
		for(int j=0;j<=6;j++)a[i][j]=0;
	}
	bool operator <(const node &o)const{
		bool flag=1;
		for(int i=1;i<=6;i++){
			for(int j=1;j<=6;j++)if(a[i][j]<o.a[i][j]){flag=0;break;}
			if(!flag)break;
		}
		return flag;
	}
	bool operator ==(const node &o)const{
		bool flag=1;
		for(int i=1;i<=6;i++){
			for(int j=1;j<=6;j++)if(a[i][j]!=o.a[i][j]){flag=0;break;}
			if(!flag)break;
		}
		return flag;
	}
};
set<node>st;
typedef set<node>::iterator IT;
void init(){
	for(int i=1;i<=6;i++)
	for(int j=1;j<=6;j++)cin>>a_[i][j];
	for(int i=1;i<=6;i++)
	for(int j=1;j<=6;j++)if(a_[i][j]&&v[a_[i][j]].u==-1){
		int t=a_[i][j];
		if(a_[i-1][j]==a_[i][j]||a_[i+1][j]==a_[i][j]){
			v[t].u=0;
			v[t].pos=j;
			for(int k=1;k<=6;k++)if(a_[k][j]==t){
				v[t].s=min(v[t].s,k);
				v[t].t=max(v[t].t,k);
				v[t].len++;
			}
		}else{
			v[t].u=1;
			v[t].pos=i;
			for(int k=1;k<=6;k++)if(a_[i][k]==t){
				v[t].s=min(v[t].s,k);
				v[t].t=max(v[t].t,k);
				v[t].len++;
			}
		}
		cnt=max(cnt,t);
	}
	sum=7-v[1].s;
}
queue<node>q;
void bfs(){
	node now,nxt;
	IT it;
	int pos;
	for(int i=1;i<=cnt;i++)now.v[i]=v[i];
	for(int i=1;i<=6;i++)
	for(int j=1;j<=6;j++)now.a[i][j]=a_[i][j];
	now.step=0;
	q.push(now);
	st.insert(now);
	while(!q.empty()){
		nxt=now=q.front();q.pop();
		int flag=1;
		for(int i=now.v[1].t+1;i<=6;i++)if(now.a[3][i])flag=0;
		if(flag){
			ans=sum+now.step;
			return;
		}
		if(sum+now.step==11)break;
		if(sum+now.step==10)continue;
		for(int k=1;k<=cnt;k++){
			pos=v[k].pos;
			for(int i=now.v[k].s-1;i<=now.v[k].s-1&&i>=1;i++){
				if(v[k].u==1){//位于同一行
					if(now.a[pos][i])continue;
					nxt.step++;
					swap(nxt.a[pos][i],nxt.a[pos][now.v[k].t]);
					nxt.v[k].s--;
					nxt.v[k].t--;
					it=st.lower_bound(nxt);
					if(it!=st.end()&&!(*it==nxt)){
						q.push(nxt);
						st.insert(nxt);
					}
					nxt.step--;
					swap(nxt.a[pos][i],nxt.a[pos][now.v[k].t]);
					nxt.v[k].s++;
					nxt.v[k].t++;
				}else{//位于同一列
					if(now.a[i][pos])continue;
					nxt.step++;
					swap(nxt.a[i][pos],nxt.a[now.v[k].t][pos]);
					nxt.v[k].s--;
					nxt.v[k].t--;
					it=st.lower_bound(nxt);
					if(it!=st.end()&&!(*it==nxt)){
						q.push(nxt);
						st.insert(nxt);
					}
					nxt.step--;
					swap(nxt.a[i][pos],nxt.a[now.v[k].t][pos]);
					nxt.v[k].s++;
					nxt.v[k].t++;
				}
			}
			for(int i=now.v[k].t+1;i<=now.v[k].t+1&&i<=6;i++){
				if(v[k].u==1){//位于同一行
					if(now.a[pos][i])continue;
					nxt.step++;
					swap(nxt.a[pos][i],nxt.a[pos][now.v[k].s]);
					nxt.v[k].s++;
					nxt.v[k].t++;
					it=st.lower_bound(nxt);
					if(it!=st.end()&&!(*it==nxt)){
						q.push(nxt);
						st.insert(nxt);
					}
					nxt.step--;
					swap(nxt.a[pos][i],nxt.a[pos][now.v[k].s]);
					nxt.v[k].s--;
					nxt.v[k].t--;
				}else{//位于同一列
					if(now.a[i][pos])continue;
					nxt.step++;
					swap(nxt.a[i][pos],nxt.a[now.v[k].s][pos]);
					nxt.v[k].s++;
					nxt.v[k].t++;
					it=st.lower_bound(nxt);
					if(it!=st.end()&&!(*it==nxt)){
						q.push(nxt);
						st.insert(nxt);
					}
					nxt.step--;
					swap(nxt.a[i][pos],nxt.a[now.v[k].s][pos]);
					nxt.v[k].s--;
					nxt.v[k].t--;
				}
			}
		}
		
	}
}
int main(){
	init();
	bfs();
	if(ans>10)ans=-1;
	cout<<ans;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linkscx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值