题意:给一段折线,可以自交,保证首尾重合,把它的轮廓求出来
链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31691
解法:参照大白书的做法,先选一个起点,即最左下角的点,再选第一条出边,即角度最小点边,开始走,找到所有与该边相交的点但不和该边起点一样交点,找到最近的一个,如果有多个,找到出去方向拐向最右的一个,不断地找,直到回到最初起点为止。。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
#define N 200
int n;
const double eps = 1e-8, pi = acos(-1.0);
int sgn(double x){
if(abs(x) < eps) return 0;
else return x > 0 ? 1 : -1;
}
struct Point{
double x, y;
Point(){};
Point(double x1, double y1){
x = x1, y = y1;
}
};
typedef Point Vector;
Vector operator - (Vector a, Vector b){
return Vector(a.x - b.x, a.y - b.y);
}
Vector operator + (Vector a, Vector b){
return Vector(a.x + b.x, a.y + b.y);
}
double operator % (Vector a, Vector b){
return a.x * b.y - a.y * b.x;
}
Vector operator * (Vector a, double b){
return Vector(a.x * b, a.y * b);
}
bool operator == (Point a, Point b){
return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
}
Point getp(Point p1, Vector v1, Point p2, Vector v2, double &t){
t = ((p2 - p1) % v2) / (v1 % v2);
return p1 + v1 * t;
}
Point p[N];
bool inter(Point p1, Point p2, Point q1, Point q2){
double t;
if(sgn((p2 - p1) % (q2 - q1)) == 0) return false;
getp(p1, p2 - p1, q1, q2 - q1, t);
if(sgn(t) < 0 || sgn(t - 1) > 0) return false;
getp(q1, q2 - q1, p1, p2 - p1, t);
if(sgn(t) < 0 || sgn(t - 1) > 0) return false;
return true;
}
double angle(Vector v1, Vector v2){
double a = atan2(v1.y, v1.x) - atan2(v2.y, v2.x);
while(sgn(a) < 0) a += 2 * pi;
while(sgn(a - 2 * pi) >= 0) a -= 2 * pi;
a = min(a, 2 * pi - a);
return - sgn(v1 % v2) * a;
}
void newp(Point &p1, Point &p2){
double mind = 1e9, t, maxa = -100;
Point newp1 = Point(-1e9, -1e9), newp2 = Point(-1e9, -1e9);
for(int i = 0; i < n; i++){
int j = i + 1 == n ? 0 : i + 1;
if(sgn((p2 - p1) % (p[j] - p[i])) == 0) continue;
if(p1 == p[i] || p1 == p[j]) continue;//!!
if(inter(p1, p2, p[i], p[j]))
{
if((p2 == p[i]) == 0)
{
Point x = getp(p1, p2 - p1, p[j], p[i] - p[j], t);
if((x == p1) == 0)
{
double a = angle(p2 - p1, p[i] - p[j]);
if(sgn(t - mind) < 0){
mind = t;
maxa = a;
newp1 = x, newp2 = p[i];
}
else if(sgn(t - mind) == 0 && sgn(a - maxa) > 0){
maxa = a;
newp1 = x, newp2 = p[i];
}
}
}
if((p2 == p[j]) == 0)
{
Point x = getp(p1, p2 - p1, p[i], p[j] - p[i], t);
if((x == p1) == 0)
{
double a = angle(p2 - p1, p[j] - p[i]);
if(sgn(t - mind) < 0){
mind = t;
maxa = a;
newp1 = x, newp2 = p[j];
}
else if(sgn(t - mind) == 0 && sgn(a - maxa) > 0){
maxa = a;
newp1 = x, newp2 = p[j];
}
}
}
}
}
p1 = newp1, p2 = newp2;
}
int main(){
while(scanf("%d",&n) == 1){
for(int i = 0; i < n; i++){
int x, y;
scanf("%d%d",&x,&y);
p[i] = Point(x, y);
}
int w = 0;
Point minp = Point(1e9, 1e9);
for(int i = 0; i < n; i++){
if(sgn(p[i].x - minp.x) < 0){
w = i;
minp = p[i];
}
else if(sgn(p[i].x - minp.x) == 0 && sgn(p[i].y - minp.y) < 0){
w = i;
minp = p[i];
}
}
Point p1 = p[w] - Vector(0, 1), p2 = p[w];
newp(p1, p2);
vector<Point>res;
res.clear();
while(true){
res.push_back(p1);
newp(p1, p2);
if(p1 == minp) break;
}
printf("%d\n", (int) res.size());
for(int i = 0; i < res.size(); i++){
printf("%.4f %.4f\n", res[i].x, res[i].y);
}
}
return 0;
}