题目大意:
给出空间中 n(1≤n≤100) 个点,求出其凸包。如果有点在凸包的面或棱上,也要将其算进凸包中,将答案按字典序输出。
分析:
首先我就不吐槽 sgu 坑爹的输入了...
主要就是求解三维凸包,至于凸包面或棱上的点可以在求出凸包后再加进去。凸包上每个面都是三角形,如果在平面中就类似三角剖分一般。
这里采用的是O(n2)的增量法,主要算法流程就是:
(1) 初始化一个未退化的四面体;
(2) 如果新点在凸包内或凸包上,忽视掉;
(3) 如果新点在凸包外,删去它可以看到的面,并将其并入整个凸包中。
对于 (1) 我们要对三点共线,四点共面的情况分别判断。
对于 (2) 主要就是我们维护凸包上每个面的法向量朝外,通过对点积判断正负来判断是否能看到该面。对于由 A,B,C 构成的法向量为 law?→? 的三角形,如果点 P 能看到该面当且仅当 AP?→??law?→?>0 ,如果一个面都看不到,那么说明该点在凸包内。
对于 (3) 就是把能看到的面删去,同时将点 P 与凸包未被删去的轮廓相连,也就是那些只被删去过一次的边。
有图有真相:
AC code:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <string>
#include <sstream>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#define vec pot
#define sqr(x) ((x)*(x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
#define mp make_pair
#define clr(a, b) memset(a, b, sizeof a)
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
#define sqr(x) ((x)*(x))
typedef long long LL;
typedef double DB;
typedef long double LD;
using namespace std;
void open_init()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
}
void close_file()
{
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
}
const int MAXN = 109;
int n;
string input;
string name[MAXN];
string ansn[MAXN];
int tot;
struct pot
{
LL x, y, z;
pot(LL x = 0, LL y = 0, LL z = 0):x(x),y(y),z(z){}
friend pot operator + (const pot &a, const pot &b)
{
return pot(a.x+b.x, a.y+b.y, a.z+b.z);
}
friend pot operator - (const pot &a, const pot &b)
{
return pot(a.x-b.x, a.y-b.y, a.z-b.z);
}
friend LL operator * (const pot &a, const pot &b)
{
return a.x*b.x+a.y*b.y+a.z*b.z;
}
friend pot operator ^ (const pot &a, const pot &b)
{
return pot(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);
}
}v[MAXN];
struct tri
{
int p[4];
pot law;
};
tri s[MAXN*MAXN];
int stot;
set<int> valid, ans;
int bel[MAXN][MAXN];
bool del[MAXN*MAXN];
queue<int> q;
inline void read(int &pos, LL &x)
{
int tmp = pos, i, f = 1;x = 0;
while(input[pos] == ‘-‘ || isdigit(input[pos])) pos--;
i = pos+1, pos--;
if(input[i] == ‘-‘) f = -1;
else x = input[i]-‘0‘;
while(isdigit(input[++i])) x = x*10+input[i]-‘0‘;
x *= f;
}
inline bool zero(const pot &a)
{
return !a.x && !a.y && !a.z;
}
inline bool collinear(int a, int b, int c)
{
return zero((v[a]-v[b])^(v[a]-v[c]));
}
inline bool coplanar(int a, int b, int c, int d)
{
return ((v[b]-v[a])^(v[c]-v[a]))*(v[d]-v[a]) == 0;
}
inline void end()
{
cout << n << endl;
sort(name+1, name+n+1);
rep(i, 1, n)
cout << name[i] << endl;
exit(0);
}
pot law(int a, int b, int c)
{
return (v[b]-v[a])^(v[c]-v[a]);
}
inline void add(int a, int b, int c)
{
tri node;
node.p[3] = node.p[0] = a, node.p[1] = b, node.p[2] = c;
node.law = law(a, b, c);s[++stot] = node;valid.insert(stot);
rep(i, 0, 2) bel[node.p[i]][node.p[i+1]] = stot;
}
inline void init(int a, int b, int c, int d)
{
if(law(a, b, c)*(v[d]-v[a]) < 0) add(a, b, c);
else add(a, c, b);
}
inline bool in(int a, int b, int c, int d)
{
return ((v[b]-v[a])^(v[d]-v[a]))*((v[d]-v[a])^(v[c]-v[a])) >= 0;
}
inline bool in_tri(const tri &a, int b)
{
int x(a.p[0]), y(a.p[1]), z(a.p[2]);
if(!coplanar(a.p[0], a.p[1], a.p[2], b)) return false;
return in(x, y, z, b) && in(y, z, x, b) && in(z, x, y, b);
}
int main()
{
open_init();
scanf("%d\n", &n);
rep(i, 1, n)
{
char c;
getline(cin, input);
int j = input.size()-1;
while((c=input[j]) == ‘\n‘ || c == ‘\r‘ || c == ‘ ‘)
j--;
read(j, v[i].z), read(j, v[i].y), read(j, v[i].x);
name[i] = input.substr(0, j+1);
}
if(n == 1) end();
int ch1 = 0;
rep(i, 3, n)
if(!collinear(1, 2, i))
{
ch1 = i;
break;
}
if(!ch1) end();
int ch2 = 0;
rep(i, 3, n)
if(i != ch1 && !coplanar(1, 2, ch1, i))
{
ch2 = i;
break;
}
if(!ch2) end();
init(1, 2, ch1, ch2), init(1, 2, ch2, ch1);
init(2, ch1, ch2, 1), init(1, ch1, ch2, 2);
set<int>::iterator it;
rep(i, 3, n)
if(i != ch1 && i != ch2)
{
bool flag = false;
for(it = valid.begin(); it != valid.end(); ++it)
if(s[*it].law*(v[i]-v[s[*it].p[0]]) > 0)
{
flag = true;
q.push(*it);
del[*it] = true;
}
if(!flag) continue;
while(!q.empty())
{
int now = q.front();q.pop();
valid.erase(now);
rep(j, 0, 2)
if(!del[bel[s[now].p[j+1]][s[now].p[j]]])
add(i, s[now].p[j], s[now].p[j+1]);
}
}
for(it = valid.begin(); it != valid.end(); ++it)
rep(i, 0, 2)
ans.insert(s[*it].p[i]);
rep(i, 1, n)
if(!ans.count(i))
for(it = valid.begin(); it != valid.end(); ++it)
if(in_tri(s[*it], i))
ans.insert(i);
for(it = ans.begin(); it != ans.end(); ++it)
ansn[++tot] = name[*it];
cout << tot << endl;
sort(ansn+1, ansn+tot+1);
rep(i, 1, tot)
cout << ansn[i] << endl;
close_file();
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-08 02:22:23