SGU128 Snake

时间:2024-12-11 00:06:56

SGU128,题意是给定N个点,问说能不能形成一个闭环G,要求G经过每个点,且在每个点处都有90度的转角,且不能出现自交。

没想出来,通过提供的思路,由于每个点处都需要90度的转弯,因此每个点处必然有一条横向以及一条纵向的路径穿过,单从某个x来看,由于上述限制,因此需要有偶数个点两两配对。然后通过搜索判断是否连通,最后再借助树状数组判断是否有自交的情况(”+”这种自交形状)出现。

PS: 里有个GDB的简单教程。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std; const int MAXN = ; pair<int, int> points[MAXN];
vector<int> x_points[*MAXN], y_points[*MAXN];
int x_link[MAXN], y_link[MAXN];
bool visit[MAXN], towards[*MAXN]; class BinaryIndexedTree {
private:
int *c_, num_;
public:
BinaryIndexedTree() : c_(NULL) {}
BinaryIndexedTree(int num) : num_(num) {
c_ = new int[num_];
memset(c_, , sizeof(int) * num_);
}
~BinaryIndexedTree() {
if (c_ != NULL) {
delete[] c_;
c_ = NULL;
}
}
private:
int lowbit(int x) {
return x & (-x);
}
public:
int Query(int i) {
int res = ;
while (i > ) {
res += c_[i];
i -= this->lowbit(i);
}
return res;
}
int Query(int left, int right) {
return this->Query(right) - this->Query(left - );
}
void Update(int i, int value) {
while (i < num_) {
c_[i] += value;
i += this->lowbit(i);
}
}
}; bool x_cmp(int u, int v) {
return points[u].first < points[v].first;
} bool y_cmp(int u, int v) {
return points[u].second < points[v].second;
} int main()
{
int n;
scanf("%d", &n);
for (int i = ; i < n; i++) {
int a, b;
scanf("%d%d", &a, &b);
a += ;
b += ; points[i].first = a;
points[i].second = b; x_points[a].push_back(i);
y_points[b].push_back(i);
} bool ok = true;
int total_length = ;
memset(x_link, -, sizeof(x_link));
memset(y_link, -, sizeof(y_link)); do {
// x order
for (int i = ; i < * MAXN; i++) {
if (x_points[i].size() > ) {
if (x_points[i].size() & ) {
ok = false;
break;
} sort(x_points[i].begin(), x_points[i].end(), y_cmp); for (int j = ; j < x_points[i].size(); j += ) {
int down = x_points[i][j];
int up = x_points[i][j + ]; total_length += (points[up].second - points[down].second); y_link[down] = up; y_link[up] = down;
}
}
}
if (!ok) break; // y order
for (int i = ; i < * MAXN; i++) {
if (y_points[i].size() > ) {
if (y_points[i].size() & ) {
ok = false;
break;
} sort(y_points[i].begin(), y_points[i].end(), x_cmp); for (int j = ; j < y_points[i].size(); j += ) {
int left = y_points[i][j];
int right = y_points[i][j + ]; total_length += (points[right].first - points[left].first); x_link[left] = right; x_link[right] = left;
}
}
}
if (!ok) break; // search
memset(visit, false, sizeof(visit));
vector<int> Q;
Q.push_back();
visit[] = true; for (int i = ; i < Q.size(); i++) {
if (x_link[Q[i]] == - || y_link[Q[i]] == -) {
ok = false;
break;
} else {
if (visit[x_link[Q[i]]] == false) {
visit[x_link[Q[i]]] = true;
Q.push_back(x_link[Q[i]]);
} if (visit[y_link[Q[i]]] == false) {
visit[y_link[Q[i]]] = true;
Q.push_back(y_link[Q[i]]);
}
}
} for (int i = ; i < n; i++) {
if (visit[i] == false) {
ok = false;
break;
}
} // check self-cross
memset(towards, false, sizeof(towards));
BinaryIndexedTree tree = BinaryIndexedTree(MAXN * );
for (int i = ; i < *MAXN; i++) if (x_points[i].size() > ) {
for (int j = ; j < x_points[i].size(); j += ) {
int down = points[x_points[i][j]].second;
int up = points[x_points[i][j + ]].second; towards[down] = !towards[down];
towards[up] = !towards[up]; tree.Update(down, towards[down] ? + : -);
tree.Update(up, towards[up] ? + : -); if (down + < up - && tree.Query(down + , up - ) > ) {
ok = false;
break;
}
} if (!ok) break;
} } while(); if (ok) {
printf("%d\n", total_length);
} else {
printf("0\n");
}
}