SPOJ LAS(BFS)

本文介绍了解决一道BFS搜索难题的过程,通过加入剪枝策略显著提升了算法效率,避免了重复节点的扩展,降低了时间复杂度至O(n*m)。

点击打开链接

上面两题是这题的弱化版本,这次,这道题目的难度继续增加。依然是BFS搜索。我当时调试了一天,wa了19发,在第20发加了个剪枝终于过去了。

坑点,上面两题的坑点他肯定是有的。但是这次如果直接拿上面题目的解法来写,会不断的TLE,原因就是上面两道题我没有剪枝,这道题不剪枝过不了。

他有一种情况就是发射后两束激光又汇聚到了某个点,那么这个点第二次你是不用加进去的(在他们达到这个点步数相同的前提下),否则的话跑下来就会有很多点是这样重复并且不断重复扩展,这样极其浪费时间。我们要做的就是,既要保证激光可以继续向前查看是否可以遍历,又不加进这个重复的点(特判一下就好了)。

剪枝后复杂度极低,是O(n*m),每个点只加进去一次且跑一次就好了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
char G[205][205];
int d[4][2] = {-1,0, 0,1, 1,0, 0,-1};
int sx, sy, ex, ey, n, m;
int front_x[205][205], front_y[205][205], cnt[205][205], director[205][205];

struct node
{
	int step;
	int x, y;
	bool operator < (const node &a)const
	{
		if(a.step == step)
		{
			if(a.x == x)
				return y > a.y;
			return x > a.x;
		}
		return step > a.step;
	}
};

priority_queue <node> q;

bool Check(int x, int y, int step)
{
	if(x >= 0 && x < n && y >= 0 && y < m && G[x][y] != '#' && (cnt[x][y] == -1 || cnt[x][y] == step))
		return 1;
	return 0;
}

void add(int x, int y, int dir, int step)
{
	int tx, ty;
	node tmp;
	tx = x; 
	ty = y;
	x += d[dir][0];
	y += d[dir][1];
	while(Check(x, y, step))
	{
		if(cnt[x][y] != step)
		{
			cnt[x][y] = step;
			front_x[x][y] = tx;
			front_y[x][y] = ty;
			director[x][y] = dir;
			tmp.x = x;
			tmp.y = y;
			tmp.step = step;
			q.push(tmp);
		}
		
		tx = x; 
		ty = y;
		x += d[dir][0];
		y += d[dir][1];
	}
}

char Find_dir(int x, int y, int d1, int d2)
{
	if((d1 == 1 && d2 == 0) || (d1 == 0 && d2 == 1))
		return '/';
	else if((d1 == 2 && d2 == 3) || (d1 == 3 && d2 == 2))
		return '/';
	else if((d1 == 0 && d2 == 3) || (d1 == 3 && d2 == 0))
		return '\\';
	else if((d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1))
		return '\\';
	else
		return G[x][y];
}

void bfs(int dir)
{
	while(!q.empty())
		q.pop();
		
	node now, next;
	cnt[sx][sy] = 100000;
	add(sx, sy, dir, 0);
	
	while(!q.empty())
	{
		now = q.top();
		q.pop();
		if(now.x == ex && now.y == ey)
		{
			int tx = ex, ty = ey;
			ex = front_x[tx][ty];
			ey = front_y[tx][ty];
			while(ex != sx || ey != sy)
			{	
				if(director[ex][ey] != director[tx][ty])
					G[ex][ey] = Find_dir(ex, ey, director[ex][ey], director[tx][ty]);
				tx = ex;
				ty = ey;
				ex = front_x[tx][ty];
				ey = front_y[tx][ty];
			}
			return;
		}
		next.step = now.step + 1;
		for(int i = 0; i < 4; i++)
		{
			next.x = now.x + d[i][0];
			next.y = now.y + d[i][1];
			if(Check(next.x, next.y, next.step))
			{
				add(now.x, now.y, i, next.step);
			}
		}
	}
}

int main()
{
	int T;
	long long room = sizeof(cnt);
	scanf("%d", &T);
	while(T--)
	{
//		memset(vst, 0, sizeof(vst));
		memset(cnt, -1, room);
		scanf("%d%d", &n, &m);
		for(int i = 0; i < n; i++)
		{
			scanf("%s", &G[i]);
			for(int j = 0; j < m; j++)
			{
				if(G[i][j] == '>' || G[i][j] == '<' || G[i][j] == '^' || G[i][j] == 'v')
				{
					sx = i;
					sy = j;
				}
				if(G[i][j] == 'C')
				{
					ex = i;
					ey = j;
				}
			}
		}
		int dir;
		if(G[sx][sy] == '>')
			dir = 1;
		else if(G[sx][sy] == '<')
			dir = 3;
		else if(G[sx][sy] == '^')
			dir = 0;
		else if(G[sx][sy] == 'v')
			dir = 2;
		bfs(dir);
		for(int i = 0; i < n; i++)
			printf("%s\n", G[i]);
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值