P3829 [SHOI2012]信用卡凸包

凸包练习题

凸包模板 + 初中几何知识。

难在将中点坐标转化成四角坐标。

注意:信用卡有 $N$ 个,所以点的坐标也就有 $4N$ 个,所以数组空间要开 $4$ 倍大小。

AC Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<iomanip>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define gh() getchar()
#define re register
#define db double
typedef long long ll;
using namespace std;
const int MAXN=4e4+1;
const int dx[]={0,1,-1,1,-1};
const int dy[]={0,1,1,-1,-1};
template<class T>
inline void read(T &x)
{
x=0;
char ch=gh(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=gh();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
template<class T>
inline bool checkMax(T &x,T &y)
{
return x<y?x=y,1:0;
}
template<class T>
inline bool checkMin(T &x,T &y)
{
return x>y?x=y,1:0;
}
int N,cnt;
double len,wid,rth;
struct Point
{
double x,y;
Point operator-(const Point &a)const
{
return {x-a.x,y-a.y};
}
Point(double x=0,double y=0):x(x),y(y){}
}Pt[MAXN],centre[MAXN];
inline double cross(Point a,Point b)
{
return a.x*b.y-a.y*b.x;
}
inline double area(Point a,Point b,Point c)
{
return cross(b-a,c-a);
}
inline Point rotate(Point a,double alph)
{
return {a.x*cos(alph)+a.y*sin(alph),-a.x*sin(alph)+a.y*cos(alph)};
}
double theta[MAXN];
inline void init()
{
for(int i=1;i<=N;++i)
for(int k=1;k<=4;++k)
{
Point dis=rotate({dx[k]*len,dy[k]*wid},-theta[i]);
Pt[++cnt]=Point(centre[i].x+dis.x,centre[i].y+dis.y);
}
// for(int i=1;i<=cnt;++i) printf("%.2lf %.2lf\n",Pt[i].x,Pt[i].y);
}
int stk[MAXN<<1],top;
bool used[MAXN];
inline bool cmp(Point a,Point b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
inline double getDist(Point a,Point b)
{
return std::sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline void andrew()
{
std::sort(Pt+1,Pt+1+cnt,cmp);
top=0;
for(int i=1;i<=cnt;++i)
{
while(top>=2)
{
double res=area(Pt[stk[top-1]],Pt[stk[top]],Pt[i]);
if(res<0) used[stk[top--]]=0;
else if(res==0) --top;
else break;
}
stk[++top]=i;
used[i]=1;
}
used[1]=0;
for(int i=cnt;i>=1;--i)
{
if(used[i]) continue;
while(top>=2&&area(Pt[stk[top-1]],Pt[stk[top]],Pt[i])<0) --top;
stk[++top]=i;
}
double res=0;
for(int i=2;i<=top;++i) res+=getDist(Pt[stk[i-1]],Pt[stk[i]]);
printf("%.2lf",res+(2*rth*acos(-1)));
}
int main()
{
// freopen("geo.in","r",stdin);
// freopen("geo.out","w",stdout);
read(N);
scanf("%lf%lf%lf",&wid,&len,&rth);
wid=(wid-2*rth)/2;
len=(len-2*rth)/2;
for(int i=1;i<=N;++i) scanf("%lf%lf%lf",&centre[i].x,&centre[i].y,&theta[i]);
init();
andrew();
return 0;
}
/*
2
6.0 2.0 0.0
0.0 0.0 0.0
2.0 -2.0 1.5707963268
*/