poj3293(幾何掃描線+並查集)

/*
translation:
	給定N個點,問是否能組成直角多邊形(每個頂點都與另外兩個頂點構成直角,每條邊都平行於座標軸),並求出周長
solution:
	掃描線,並查集
	橫着掃描一遍,並將縱座標相同的相鄰兩個點連起來,如果到最後剩下一個單獨的點,那麼答案肯定就爲-1.豎直方向一樣處理。
	注意最後還要判斷是否聯通(考慮用並查集)以及橫線和豎線是否有相交。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>

using namespace std;
const int maxn = 100000 + 5;

struct Point
{
	int x, y, id;
	Point(){}
	Point(int x, int y):x(x),y(y),id(id){}
} p[maxn];

struct Line
{
	int x0, y0, x1, y1;
	Line(){}
	Line(int x0, int y0, int x1, int y1):x0(x0),y0(y0),x1(x1),y1(y1){}
};
vector<Line> line;

int n;
bool horizontal[maxn], vertical[maxn];

bool cmpX(const Point& lhs, const Point& rhs)
{
	return lhs.x < rhs.x || (lhs.x == rhs.x && lhs.y < rhs.y);
}

bool cmpY(const Point& lhs, const Point& rhs)
{
	return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x);
}

int parent[maxn], high[maxn];

int getRoot(int x)
{
	if(parent[x] == x)	return x;
	return parent[x] = getRoot(parent[x]);
}

void unite(int u, int v)
{
	u = getRoot(u);
	v = getRoot(v);
	if(u == v)	return;

	if(high[u] < high[v])	parent[u] = v;
	else {
		parent[v] = u;
		if(high[u] == high[v])	high[u]++;
	}
}

inline int dist(int x0, int y0, int x1, int y1)
{
	if(x0 == x1)	return abs(y0 - y1);
	else			return abs(x0 - x1);
}

bool check(int x0, int x1, int y1)
{
	for(int i = 0; i < line.size(); i++) {
		if(y1 > line[i].y0 && y1 < line[i].y1 && line[i].x0 > x0 && line[i].x1 < x1)
			return false;
	}
	return true;
}

int solve()
{
	int res = 0;
	sort(p, p + n, cmpX);
	for(int i = 1; i < n; i++) {
		if(p[i].x == p[i-1].x) {
			if(!vertical[i-1] && !vertical[i]) {
				vertical[i] = vertical[i-1] = true;
				unite(p[i].id, p[i-1].id);
				res += dist(p[i-1].x, p[i-1].y, p[i].x, p[i].y);
				line.push_back(Line(p[i-1].x, p[i-1].y, p[i].x, p[i].y));
			}
		}
	}

	sort(p, p + n, cmpY);
	for(int i = 1; i < n; i++) {
		if(p[i].y == p[i-1].y) {
			if(!horizontal[i-1] && !horizontal[i]) {
				if(!check(p[i-1].x, p[i].x, p[i].y))	continue;
				horizontal[i-1] = horizontal[i] = true;
				unite(p[i].id, p[i-1].id);
				res += dist(p[i-1].x, p[i-1].y, p[i].x, p[i].y);
			}
		}
	}

	for(int i = 0; i < n; i++) {
		if(!(horizontal[i] && vertical[i]))
			return -1;
	}
	for(int i = 1; i < n; i++) {
		if(getRoot(p[0].id) != getRoot(p[i].id))
			return -1;
	}
	return res;
}

int main()
{
	//freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--) {
		scanf("%d", &n);
		for(int i = 0; i < n; i++) {
			scanf("%d%d", &p[i].x, &p[i].y);
			p[i].id = i;
		}

		for(int i = 0; i < n; i++) {
			parent[i] = i;
			high[i] = 0;
		}
		memset(horizontal, 0, sizeof(horizontal));
		memset(vertical, 0, sizeof(vertical));

		line.clear();
		printf("%d\n", solve());
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章