SGU128 Snake
SGU128,题意是给定N个点,问说能不能形成一个闭环G,要求G经过每个点,且在每个点处都有90度的转角,且不能出现自交。
没想出来,通过这提供的思路,由于每个点处都需要90度的转弯,因此每个点处必然有一条横向以及一条纵向的路径穿过,单从某个x来看,由于上述限制,因此需要有偶数个点两两配对。然后通过搜索判断是否连通,最后再借助树状数组判断是否有自交的情况(”+”这种自交形状)出现。
PS: 这里有个GDB的简单教程。
#include <iostream> #include <algorithm> #include <vector> using namespace std; const int MAXN = 10005; pair<int, int> points[MAXN]; vector<int> x_points[2*MAXN], y_points[2*MAXN]; int x_link[MAXN], y_link[MAXN]; bool visit[MAXN], towards[2*MAXN]; class BinaryIndexedTree { private: int *c_, num_; public: BinaryIndexedTree() : c_(NULL) {} BinaryIndexedTree(int num) : num_(num) { c_ = new int[num_]; memset(c_, 0, 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 = 0; while (i > 0) { res += c_[i]; i -= this->lowbit(i); } return res; } int Query(int left, int right) { return this->Query(right) - this->Query(left - 1); } 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 = 0; i < n; i++) { int a, b; scanf("%d%d", &a, &b); a += 10001; b += 10001; 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 = 0; memset(x_link, -1, sizeof(x_link)); memset(y_link, -1, sizeof(y_link)); do { // x order for (int i = 0; i < 2 * MAXN; i++) { if (x_points[i].size() > 0) { if (x_points[i].size() & 1) { ok = false; break; } sort(x_points[i].begin(), x_points[i].end(), y_cmp); for (int j = 0; j < x_points[i].size(); j += 2) { int down = x_points[i][j]; int up = x_points[i][j + 1]; total_length += (points[up].second - points[down].second); y_link[down] = up; y_link[up] = down; } } } if (!ok) break; // y order for (int i = 0; i < 2 * MAXN; i++) { if (y_points[i].size() > 0) { if (y_points[i].size() & 1) { ok = false; break; } sort(y_points[i].begin(), y_points[i].end(), x_cmp); for (int j = 0; j < y_points[i].size(); j += 2) { int left = y_points[i][j]; int right = y_points[i][j + 1]; 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(0); visit[0] = true; for (int i = 0; i < Q.size(); i++) { if (x_link[Q[i]] == -1 || y_link[Q[i]] == -1) { 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 = 0; i < n; i++) { if (visit[i] == false) { ok = false; break; } } // check self-cross memset(towards, false, sizeof(towards)); BinaryIndexedTree tree = BinaryIndexedTree(MAXN * 2); for (int i = 0; i < 2*MAXN; i++) if (x_points[i].size() > 0) { for (int j = 0; j < x_points[i].size(); j += 2) { int down = points[x_points[i][j]].second; int up = points[x_points[i][j + 1]].second; towards[down] = !towards[down]; towards[up] = !towards[up]; tree.Update(down, towards[down] ? +1 : -1); tree.Update(up, towards[up] ? +1 : -1); if (down + 1 < up - 1 && tree.Query(down + 1, up - 1) > 0) { ok = false; break; } } if (!ok) break; } } while(0); if (ok) { printf("%d\n", total_length); } else { printf("0\n"); } }