/*
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;
}
poj3293(幾何掃描線+並查集)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.