Walk UVA - 1666

比较繁琐的一道题目,为了处理上的方便,我们将所有的坐标都扩大三倍,扩大三倍之后,要找出之前的起始点、终止点以及建筑物矩形所围成区域对应的坐标,注意为了建筑物矩形处理的方便,我们将左边右移、右边左移、上边下移、下边上移,然后标注好,同时要注意处理好建筑物的接触点的地方,在进行后面的遍历的时候要注意题目中讲的可以沿着边进行移动,同时要设置对应的数组,记录在每个点的每个方向上是否已经考虑到了,这样可以去重,具体实现见如下代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;

int dx[] = { -3, 0, 3, 0 };
int dy[] = { 0, 3, 0, -3 };
const int M = 350;

int record_x[M], record_y[M];
int ind_x,ind_y;
int area[M][M];
int Left[M][M], Up[M][M], Right[M][M], Down[M][M], Ban[M][M];
int visit[M][M][4];

class Node{
public:
	int x, y, dir, cnt;
	Node(int X = 0, int Y = 0, int Dir = -1, int Cnt = 0) :x(X), y(Y), dir(Dir), cnt(Cnt){}
};

class Point{
public:
	int l, r, u, d;
};

class Solve{
public:
	int startx, starty, endx, endy;
	int N;
	vector<Point> point;

	int search(int aim,bool isx){
		if (isx){
			for (int i = 1; i <= ind_x; i++){
				if (record_x[i] == aim) return i;
			}
		}
		else{
			for (int i = 1; i <= ind_y; i++){
				if (record_y[i] == aim) return i;
			}
		}
	}

	void Init(){
		cin >> N;
		point.clear();
		ind_x = 1, ind_y = 1;
		memset(area, 0, sizeof(area));
		for (int i = 1; i <= N; i++){
			int a, b, c, d;
			cin >> a >> b >> c >> d;
			Point temp;
			temp.l = min(a,c);
			temp.r = max(a,c);
			temp.d = min(b,d);
			temp.u = max(b,d);//保证了u和d的正确性
			point.push_back(temp);
			record_x[ind_x++] = a, record_x[ind_x++] = c;
			record_y[ind_y++] = b, record_y[ind_y++] = d;
		}
		record_x[ind_x++] = startx, record_x[ind_x++] = endx;
		record_y[ind_y++] = starty, record_y[ind_y++] = endy;
		ind_x--, ind_y--;
		sort(record_x+1,record_x+ind_x+1);
		sort(record_y+1,record_y+ind_y+1);
		ind_x = unique(record_x+1, record_x + ind_x+1) - (record_x+1);
		ind_y = unique(record_y+1, record_y + ind_y+1) - (record_y+1);
		startx = search(startx, true) * 3, endx = search(endx, true) * 3;
		starty = search(starty, false) * 3, endy = search(endy, false) * 3;
		memset(Left, 1, sizeof(Left)), memset(Right, 1, sizeof(Right));
		memset(Down, 1, sizeof(Down)), memset(Up, 1, sizeof(Up));
		memset(Ban, 0, sizeof(Ban));
		for (int i = 0; i < N; i++){
			int l = search(point[i].l, true) * 3 + 1;
			int r = search(point[i].r, true) * 3 - 1;
			int u = search(point[i].u, false) * 3 - 1;
			int d = search(point[i].d, false) * 3 + 1;
			for (int ind1 = l; ind1 <= r; ind1++){
				for (int ind2 = d; ind2 <= u; ind2++){
					Ban[ind1][ind2] = 1;
				}
			}
		}
		for (int i = 1; i <= ind_x; i++){
			for (int j = 1; j <= ind_y; j++){
				int newx = i * 3;
				int newy = j * 3;
				if (Ban[newx][newy] == 1) continue;
				if (Ban[newx - 1][newy - 1] && Ban[newx + 1][newy + 1]){
					Left[newx][newy] = Right[newx][newy] = Up[newx][newy] = Down[newx][newy] = 1;
				}
				if (Ban[newx - 1][newy + 1] && Ban[newx + 1][newy - 1]){
					Left[newx][newy] = Right[newx][newy] = Up[newx][newy] = Down[newx][newy] = 2;
				}
				if (Ban[newx - 1][newy + 1] && Ban[newx - 1][newy - 1]) Left[newx][newy] = 0;
				if (Ban[newx + 1][newy + 1] && Ban[newx + 1][newy - 1]) Right[newx][newy] = 0;
				if (Ban[newx + 1][newy - 1] && Ban[newx - 1][newy - 1]) Down[newx][newy] = 0;
				if (Ban[newx + 1][newy + 1] && Ban[newx - 1][newy + 1]) Up[newx][newy] = 0;
			}
		}
	}

	int Deal(){
		Init();
		memset(visit, 0, sizeof(visit));
		queue<Node> q;
		Node t(startx, starty, -1, 0);
		q.push(t);
		while (!q.empty()){
			Node temp = q.front();
			q.pop();
			if (temp.x == endx&&temp.y == endy) return temp.cnt;
			for (int i = 0; i < 4; i++){
				int newx = temp.x, newy = temp.y;
				if (i == 0 && !Left[newx][newy] || i == 1 && !Up[newx][newy] ||
					i == 2 && !Right[newx][newy] || i == 3 && !Down[newx][newy]) continue;
				if (Down[newx][newy] == 1){
					if (temp.dir == 0 && (i == 0 || i == 1)) continue;
					if (temp.dir == 1 && (i == 1 || i == 0)) continue;
					if (temp.dir == 2 && (i == 2 || i == 3)) continue;
					if (temp.dir == 3 && (i == 3 || i == 2)) continue;
				}
				if (Down[newx][newy] == 2){
					if (temp.dir == 0 && (i == 0 || i == 3)) continue;
					if (temp.dir == 3 && (i == 3 || i == 0)) continue;
					if (temp.dir == 1 && (i == 1 || i == 2)) continue;
					if (temp.dir == 2 && (i == 2 || i == 1)) continue;
				}
				newx += dx[i], newy += dy[i];
				while (newx >= 1 && newx <= ind_x * 3 && newy >= 1 && newy <= ind_y * 3 
					&& !Ban[newx][newy]){
					Node temp2;
					temp2.x = newx, temp2.y = newy;
					temp2.dir = i, temp2.cnt = temp.cnt;
					if (!visit[temp2.x][temp2.y][temp2.dir]){
						visit[temp2.x][temp2.y][temp2.dir] = 1;
						if (i != temp.dir&&temp.dir != -1) temp2.cnt++;
						q.push(temp2);
					}
					if (temp2.dir == 0 && !Left[temp2.x][temp2.y] || temp2.dir == 1 && !Up[temp2.x][temp2.y] ||
						temp2.dir == 2 && !Right[temp2.x][temp2.y] || temp2.dir == 3 && !Down[temp2.x][temp2.y]) break;
					if (Down[temp2.x][temp2.y] == 1 || Down[temp2.x][temp2.y] == 2) break;
					newx += dx[i];
					newy += dy[i];
				}
			}
		}
		return -1;
	}
};

int main(){
	Solve a;
	while (cin >> a.startx >> a.starty >> a.endx >> a.endy){
		if (a.startx == 0 && a.starty == 0 && a.endx == 0 && a.endy == 0) break;
		cout<<a.Deal()<<endl;
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值