Problem
给定 K 组三维线段 x1 y1 z1 x2 y2 z2
,判断是否存在
≥3
条边构成环。同时将三维线段投射到二维平面上,构成若干二维线段 x1 y1 x2 y2
(可能有重合),判断是否存在
≥3
条二维线段构成环。
限制条件
1 ≤ K ≤ 50000
1≤xi, yi, zi≤1000
解题思路
通过离散化将三维点和二维点作为点编号,记录二维线段和三维线段(通过两端点的编号形式保存)。DFS 深搜,标记遍历到的点的深度,若存在已记录深度的点的深度较之再次遍历到该点的深度差 ≥2 。则存在对应维度的环。
代码
#include<bits/stdc++.h>
using namespace std;
struct Node {
int x, y, z;
} p, q;
bool operator<(Node a, Node b) {
if(a.x == b.x) {
if(a.y == b.y) return a.z < b.z;
return a.y < b.y;
}
return a.x < b.x;
}
map<Node, int> d2, d3;
int K, d2idx, d3idx, vis[2][100010];
vector<int> g[2][100010];
bool isLink[2];
void dfs(int lv, int rt, int dep)
{
if(isLink[lv]) return;
vis[lv][rt] = dep;
for(int i=0;i<g[lv][rt].size();i++)
{
if(vis[lv][ g[lv][rt][i] ]) {
if(dep - vis[lv][g[lv][rt][i]] >= 2) { isLink[lv] = true; return; }
continue;
}
dfs(lv, g[lv][rt][i], dep+1);
}
}
int main()
{
scanf("%d", &K);
for(int i=1;i<=K;i++)
{
scanf("%d %d %d %d %d %d", &p.x, &p.y, &p.z, &q.x, &q.y, &q.z);
if(d3.find(p) == d3.end()) d3[p] = ++d3idx;
if(d3.find(q) == d3.end()) d3[q] = ++d3idx;
g[1][ d3[p] ].push_back(d3[q]);
g[1][ d3[q] ].push_back(d3[p]);
p.z = q.z = 0;
if(d2.find(p) == d2.end()) d2[p] = ++d2idx;
if(d2.find(q) == d2.end()) d2[q] = ++d2idx;
g[0][ d2[p] ].push_back(d2[q]);
g[0][ d2[q] ].push_back(d2[p]);
}
for(int i=1;i<=d3idx;i++)
{
if(vis[1][i]) continue;
dfs(1, i, 1);
}
for(int i=1;i<=d2idx;i++)
{
if(vis[0][i]) continue;
dfs(0, i, 1);
}
printf("%s\n%s\n", isLink[1]?"True closed chains":"No true closed chains",
isLink[0]?"Floor closed chains":"No floor closed chains");
}