(BFS+状压)AcWing1131拯救大兵瑞恩

AcWing1131拯救大兵瑞恩

思路:

先想到是用一个结构体存一个格子四周的情况和钥匙的情况,然后每次遇到门的时候要把自己有的钥匙和需要的比较。但后来想到钥匙最多只有十个,所以可以用状态压缩,每个点的钥匙和自己的钥匙可以用二进制数表示,拿钥匙就用按位或;遇到门就用按位与判断。
然后我又用结构体记录一个点四周是否有墙,结果愉快的MLE了。后来把数据自己测的时候发现跑不出结果。在后面的一个小时内,我经历了TLE,CE,IE,WA等一系列奇怪的错误结果。
因为可以走回头路,所以我开始就没有用vis数组。但是我们又可以考虑到,我们走回头路的目的是拿钥匙,所以如果我们如果遇到走到这点时,拥有这个钥匙的状态已经存在了,就没必要再走一次了,所以用一个vis[x][y][key]来记录(x,y)点拥有钥匙状态为key的情况是否已经走过。
又发现如果我们要记录一个点的四周情况是比较麻烦的,我们只需要用一个数组wall[x1][y1][x2][y2]就可以记录两个相邻格子之间的情况了。

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
const int N=1e6+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
struct edge
{
	int x,y,t,own;
};
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}},vis[20][20][1<<11]={0};
int wall[20][20][20][20],key[20][20]={0};
int n,m,p;
int bfs()
{
	queue<edge> q;
	edge now,pre,temp;
	now.x=1;
	now.y=1;
	now.t=0;
	now.own=key[1][1];
	q.push(now);
	while(!q.empty())
	{
		pre=q.front();
		q.pop();
		if(pre.x==n && pre.y==m)	
			return pre.t;
		int i;
		for(i=0;i<4;i++)
		{
			temp.x=pre.x+dis[i][0];
			temp.y=pre.y+dis[i][1];
			if(temp.x>=1 && temp.x<=n && temp.y>=1 && temp.y<=m)
			{
				int need=wall[pre.x][pre.y][temp.x][temp.y];
				if(need==0)
					continue;
				if(need==-1 || (pre.own & (1<<need))!=0)
				{
					temp.own=pre.own|key[temp.x][temp.y];
					temp.t=pre.t+1;
					if(vis[temp.x][temp.y][temp.own]==0)
					{
						vis[temp.x][temp.y][temp.own]=1;
						q.push(temp);
					}	
				}	
			}	
		}
	}
	return -1;
}
int main()
{
	int i,j,l,k,t;
	memset(wall,-1,sizeof(wall));
	scanf("%d%d%d%d",&n,&m,&p,&k);
	for(i=1;i<=k;i++)
	{
		int x1,y1,x2,y2,s;
		scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&s);
		wall[x1][y1][x2][y2]=s;
		wall[x2][y2][x1][y1]=s;
	}
	scanf("%d",&t);
	for(i=1;i<=t;i++)
	{
		int x,y,m;
		scanf("%d%d%d",&x,&y,&m);
		key[x][y]=key[x][y]|(1<<m);
	}
	int ans=bfs();
	printf("%d\n",ans);
	return 0;
}

发布了78 篇原创文章 · 获赞 0 · 访问量 1389

猜你喜欢

转载自blog.csdn.net/Z7784562/article/details/104065877
今日推荐