HDU 3685 Rotational Painting (凸包+求重心)
Rotational Painting
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2796 Accepted Submission(s): 790
Problem Description
Josh Lyman is a gifted painter. One of his great works is a glass painting. He creates some well-designed lines on one side of a thick and polygonal glass, and renders it by some special dyes. The most fantastic thing is that it can generate different meaningful paintings by rotating the glass. This method of design is called “Rotational Painting (RP)” which is created by Josh himself.
You are a fan of Josh and you bought this glass at the astronomical sum of money. Since the glass is thick enough to put erectly on the table, you want to know in total how many ways you can put it so that you can enjoy as many as possible different paintings hiding on the glass. We assume that material of the glass is uniformly distributed. If you can put it erectly and stably in any ways on the table, you can enjoy it.
More specifically, if the polygonal glass is like the polygon in Figure 1, you have just two ways to put it on the table, since all the other ways are not stable. However, the glass like the polygon in Figure 2 has three ways to be appreciated.
![]()
Pay attention to the cases in Figure 3. We consider that those glasses are not stable.
![]()
You are a fan of Josh and you bought this glass at the astronomical sum of money. Since the glass is thick enough to put erectly on the table, you want to know in total how many ways you can put it so that you can enjoy as many as possible different paintings hiding on the glass. We assume that material of the glass is uniformly distributed. If you can put it erectly and stably in any ways on the table, you can enjoy it.
More specifically, if the polygonal glass is like the polygon in Figure 1, you have just two ways to put it on the table, since all the other ways are not stable. However, the glass like the polygon in Figure 2 has three ways to be appreciated.

Pay attention to the cases in Figure 3. We consider that those glasses are not stable.

Input
The input file contains several test cases. The first line of the file contains an integer T representing the number of test cases.
For each test case, the first line is an integer n representing the number of lines of the polygon. (3<=n<=50000). Then n lines follow. The ith line contains two real number xi and yi representing a point of the polygon. (xi, yi) to (xi+1, yi+1) represents a edge of the polygon (1<=i<n), and (xn,yn) to (x1, y1) also represents a edge of the polygon. The input data insures that the polygon is not self-crossed.
For each test case, the first line is an integer n representing the number of lines of the polygon. (3<=n<=50000). Then n lines follow. The ith line contains two real number xi and yi representing a point of the polygon. (xi, yi) to (xi+1, yi+1) represents a edge of the polygon (1<=i<n), and (xn,yn) to (x1, y1) also represents a edge of the polygon. The input data insures that the polygon is not self-crossed.
Output
For each test case, output a single integer number in a line representing the number of ways to put the polygonal glass stably on the table.
Sample Input
24
0 0
100 0
99 1
1 1
6
0 0
0 10
1 10
1 1
10 1
10 0
Sample Output
23
The sample test cases can be demonstrated by Figure 1 and Figure 2 in Description part.Hint
Source
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3685
题意: 有一副玻璃画,要立在桌子上,可以在垂直于桌面的平面旋转,问有几种稳定的摆放状态。
思路:先求出重心,再求出凸包,重心对于凸包的每一条边求垂足,看垂足是否在线段上,端点不算!,统计个数就好了,注意精度。
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>
#include <map>
using namespace std;
const int N = 50005;
const double INF = 1E200;
const double EP = 1E-8;
const double PI = acos(-1.0);
int sgn(double x)
{
if(fabs(x) < EP)return 0;
if(x < 0)return -1;
else return 1;
}
struct POINT
{
double x;
double y;
POINT(double a=0, double b=0)
{
x=a; //constructor
y=b;
}
//点积
double operator *(const POINT &b)const
{
return x*b.x + y*b.y;
}
//叉积
double operator ^(const POINT &b)const
{
return x*b.y - y*b.x;
}
POINT operator -(const POINT &b)const
{
return POINT(x - b.x,y - b.y);
}
bool operator == (const POINT& t)const
{
return fabs(x-t.x) < EP && fabs(y-t.y) < EP;
}
void input()
{
scanf("%lf%lf", &x, &y);
}
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b)
{
s=a;
e=b;
}
LINESEG() { }
};
double multiply(POINT sp,POINT ep,POINT op)
{
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
double dotmultiply(POINT p1,POINT p2,POINT p0)
{
return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));
}
double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离
{
return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );
}
/*
* 求凸包,Graham算法
* 点的编号0~n-1
* 返回凸包结果Stack[0~top-1]为凸包的编号
*/
POINT list[N];
int Stack[N],top;
//相对于list[0]的极角排序
bool _cmp(POINT p1,POINT p2)
{
double tmp = (p1-list[0])^(p2-list[0]);
if(sgn(tmp) > 0)return true;
else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
return true;
else return false;
}
void Graham(int n)
{
POINT p0;
int k = 0;
p0 = list[0];
//找最下边的一个点
for(int i = 1; i < n; i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if(n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for(int i = 2; i < n; i++)
{
while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <=0)
top--;
Stack[top++] = i;
}
}
POINT bcenter(POINT pnt[], int n)
{
POINT p, s;
double tp, area = 0, tpx = 0, tpy = 0;
p.x = pnt[0].x;
p.y = pnt[0].y;
for (int i = 1; i <= n; ++i)
{
// POINT: 0 ~ n-1
s.x = pnt[(i == n) ? 0 : i].x;
s.y = pnt[(i == n) ? 0 : i].y;
tp = (p.x * s.y - s.x * p.y);
area += tp / 2;
tpx += (p.x + s.x) * tp;
tpy += (p.y + s.y) * tp;
p.x = s.x;
p.y = s.y;
}
s.x = tpx / (6 * area);
s.y = tpy / (6 * area);
return s;
}
//点到直线距离
//返回为result,是点到直线最近的点
POINT PointToLine(POINT P,LINESEG L)
{
POINT result;
double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
result.x = L.s.x + (L.e.x-L.s.x)*t;
result.y = L.s.y + (L.e.y-L.s.y)*t;
return result;
}
bool online(LINESEG l,POINT p)
{
if(p==l.s || p==l.e)return false;
return( fabs((multiply(l.e,p,l.s))<=EP) &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=EP )&&( (p.y-l.s.y)*(p.y-l.e.y)<=EP ) ) );
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf%lf",&list[i].x,&list[i].y);
POINT c = bcenter(list,n);
Graham(n);
LINESEG xian;
int ans = 0;
for(int i=0; i<top; i++)
{
int k = (i+1==top)? 0:i+1;
xian = LINESEG(list[Stack[i]],list[Stack[k]]);
POINT chui = PointToLine(c,xian);
if(online(xian,chui))
ans++;
}
printf("%d\n",ans);
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>
#include <map>
using namespace std;
const int N = 50005;
const double INF = 1E200;
const double EP = 1E-8;
const double PI = acos(-1.0);
int sgn(double x)
{
if(fabs(x) < EP)return 0;
if(x < 0)return -1;
else return 1;
}
struct POINT
{
double x;
double y;
POINT(double a=0, double b=0)
{
x=a; //constructor
y=b;
}
//点积
double operator *(const POINT &b)const
{
return x*b.x + y*b.y;
}
//叉积
double operator ^(const POINT &b)const
{
return x*b.y - y*b.x;
}
POINT operator -(const POINT &b)const
{
return POINT(x - b.x,y - b.y);
}
bool operator == (const POINT& t)const
{
return fabs(x-t.x) < EP && fabs(y-t.y) < EP;
}
void input()
{
scanf("%lf%lf", &x, &y);
}
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b)
{
s=a;
e=b;
}
LINESEG() { }
};
double multiply(POINT sp,POINT ep,POINT op)
{
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
double dotmultiply(POINT p1,POINT p2,POINT p0)
{
return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));
}
double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离
{
return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );
}
/*
* 求凸包,Graham算法
* 点的编号0~n-1
* 返回凸包结果Stack[0~top-1]为凸包的编号
*/
POINT list[N];
int Stack[N],top;
//相对于list[0]的极角排序
bool _cmp(POINT p1,POINT p2)
{
double tmp = (p1-list[0])^(p2-list[0]);
if(sgn(tmp) > 0)return true;
else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
return true;
else return false;
}
void Graham(int n)
{
POINT p0;
int k = 0;
p0 = list[0];
//找最下边的一个点
for(int i = 1; i < n; i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if(n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for(int i = 2; i < n; i++)
{
while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <=0)
top--;
Stack[top++] = i;
}
}
POINT bcenter(POINT pnt[], int n)
{
POINT p, s;
double tp, area = 0, tpx = 0, tpy = 0;
p.x = pnt[0].x;
p.y = pnt[0].y;
for (int i = 1; i <= n; ++i)
{
// POINT: 0 ~ n-1
s.x = pnt[(i == n) ? 0 : i].x;
s.y = pnt[(i == n) ? 0 : i].y;
tp = (p.x * s.y - s.x * p.y);
area += tp / 2;
tpx += (p.x + s.x) * tp;
tpy += (p.y + s.y) * tp;
p.x = s.x;
p.y = s.y;
}
s.x = tpx / (6 * area);
s.y = tpy / (6 * area);
return s;
}
//点到直线距离
//返回为result,是点到直线最近的点
POINT PointToLine(POINT P,LINESEG L)
{
POINT result;
double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
result.x = L.s.x + (L.e.x-L.s.x)*t;
result.y = L.s.y + (L.e.y-L.s.y)*t;
return result;
}
bool online(LINESEG l,POINT p)
{
if(p==l.s || p==l.e)return false;
return( fabs((multiply(l.e,p,l.s))<=EP) &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=EP )&&( (p.y-l.s.y)*(p.y-l.e.y)<=EP ) ) );
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf%lf",&list[i].x,&list[i].y);
POINT c = bcenter(list,n);
Graham(n);
LINESEG xian;
int ans = 0;
for(int i=0; i<top; i++)
{
int k = (i+1==top)? 0:i+1;
xian = LINESEG(list[Stack[i]],list[Stack[k]]);
POINT chui = PointToLine(c,xian);
if(online(xian,chui))
ans++;
}
printf("%d\n",ans);
}
return 0;
}


浙公网安备 33010602011771号