2014
03-13

# Ancient vending machine

Though the story of Shaolong Xiang, the great time-traveler, is not recorded in the history, some recent discoveries show the possibility that the ancient mystery visitor might really exist. Several months ago, a strange machine was found together with some newly unearthed terra-cotta warriors. That machine looks like a modern machine and even has some electronic parts ― that’s why people take Mr. Xiang into consideration when guessing the origin of the strange machine.

After careful examinations, scientists finally figured out what the machine is — it actually is a vending machine in Qin dynasty! There is a hole on a panel of the machine, and scientists are pretty sure that Qin people put their coins into the machine through that hole to buy things. As you know, there were too many different types of coins before Qin dynasty and Emperor Qin Shihuang didn’t like that. But scientists found an announcement made by Qin Shihuang carved on the machine, saying that any coins which can go through the hole is still legal to use. Now your task is to determine whether a certain type of coin can be put into the hole―from these results we might find some clues about the mystery time-traveler.

The hole on the panel is a polygon and all coins also have a shape of polygon. THEY ALL MAYBE CONCAVE. Scientist found out that ancient people use the vending machine this way: The panel with the hole was positioned horizontally, and the customer chose a best position above the hole to hold a coin. Then the customer dropped the coin. During the process of felling down, the coin WOULD NOT ROTATE in any direction. If the coin could go through the hole, the coin is considered “legal”. Otherwise, the coin is judged “illegal”. If the coin just merely touched the edges of the hole but was not blocked, it was considered as legal. For example, as shown in the sample input, a square coin with side length 5 can go through a triangle hole with sides of length 3, 4 and 5 , so it’s legal.

Please note that coins and the panel are all considered as no thickness.

The first line contains an integer T representing the number of test cases( 0 < T <= 20).
For each test case, the first line contains an integer N (3<=N<=20), representing the number of vertexes of the hole-polygon.
Next N lines describe the shape of the hole-polygon by listing positions of all vertexes in counterclockwise order. Each line contains two real numbers r1 and r2 ( -100 <= r1,r2 <=100), describing the position of a vertex.

The next line contains an integer M (3<=M<=20), representing the number of vertexes of the coin-polygon.

Next M lines describe the shape of the coin-polygon by listing positions of all vertexes in counterclockwise order. Each line contains two real numbers r1 and r2 ( -100 <= r1,r2 <=100), describing the position of a vertex.

The positions mentioned above are relative coordinates but not absolute values.

The first line contains an integer T representing the number of test cases( 0 < T <= 20).
For each test case, the first line contains an integer N (3<=N<=20), representing the number of vertexes of the hole-polygon.
Next N lines describe the shape of the hole-polygon by listing positions of all vertexes in counterclockwise order. Each line contains two real numbers r1 and r2 ( -100 <= r1,r2 <=100), describing the position of a vertex.

The next line contains an integer M (3<=M<=20), representing the number of vertexes of the coin-polygon.

Next M lines describe the shape of the coin-polygon by listing positions of all vertexes in counterclockwise order. Each line contains two real numbers r1 and r2 ( -100 <= r1,r2 <=100), describing the position of a vertex.

The positions mentioned above are relative coordinates but not absolute values.

2
4
0 0
4 0
4 1
0 1
3
0 4
1 4
1 0
3
0 0
4 0
0 3
4
0 0
5 0
5 5
0 5

legal
legal

1.对于多边形A，构造凸包利用，旋转卡壳求出对踵点对，然后求出最小的高。

2. 对于多边形B，所求的最长线段，一定经过多边形上的至少两个点，枚举所有点对，计算被截取的最长部分即可。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;

typedef struct pnode
{
double x,y,d;
pnode( double a, double b ) {x = a;y = b;}
pnode(){};
}point;
point H[ 21 ];
point C[ 21 ];
point P0,Pn;

typedef struct lnode
{
double x,y,dx,dy,d;
int    id,hit,sign;
lnode( point a, point b ) {x = a.x;y = a.y;dx = b.x-a.x;dy = b.y-a.y;}
lnode(){};
}line;

//两点间距离
double dist( point a, point b )
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

//点到直线距离
double dist( point a, line l )
{
return fabs(l.dx*(a.y-l.y)-l.dy*(a.x-l.x))/sqrt(l.dx*l.dx+l.dy*l.dy);
}

//叉乘 ab*ac
double crossproduct( point a, point b, point c )
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

//坐标排序
bool cmp1( point a, point b )
{
if ( a.x == b.x ) return a.y < b.y;
else return a.x < b.x;
}

//级角排序
bool cmp2( point a, point b )
{
double cp = crossproduct( P0, a, b );
if ( cp == 0 ) return a.d < b.d;
else return cp > 0;
}

//凸包扫描算法
double Graham( int N )
{
sort( C+0, C+N, cmp1 );
P0 = C[0];
for ( int i = 1 ; i < N ; ++ i )
C[i].d = dist( P0, C[i] );
sort( C+1, C+N, cmp2 );

//计算凸包
int top = 2;
for ( int i = 3 ; i < N ; ++ i ) {
while ( top > 0 && crossproduct( C[top-1], C[top], C[i] ) <= 0 ) -- top;
C[++ top] = C[i];
}
C[++ top] = C[0];

//旋转卡壳，求对踵点对
int    L = 0,R = 1;
double D = 500.000;
do{
while ( crossproduct( C[R], C[L], C[(L+1)%top] ) <= crossproduct( C[(R+1)%top], C[L], C[(L+1)%top] ) )
R = (R+1)%top;

D = min( D, dist( C[R], line( C[L], C[(L+1)%top] ) ) );
L = (L+1)%top;
}while ( L );

return D;
}

//直线与线段相交判断
bool l_cross_s( line b, line a )
{
double t1 = b.dx*(a.y-b.y)-b.dy*(a.x-b.x);
double t2 = b.dx*(a.y+a.dy-b.y)-b.dy*(a.x+a.dx-b.x);
return t1*t2 < 0;
}

//线段相交
bool s_cross_s( line a, line b )
{
double t1 = 0.0+a.dx*(b.y-a.y)-a.dy*(b.x-a.x);
double t2 = 0.0+a.dx*(b.y+b.dy-a.y)-a.dy*(b.x+b.dx-a.x);
double t3 = 0.0+b.dx*(a.y-b.y)-b.dy*(a.x-b.x);
double t4 = 0.0+b.dx*(a.y+a.dy-b.y)-b.dy*(a.x+a.dx-b.x);
return (t1*t2 < 0)&&(t3*t4 < 0);
}

//点在线段上
bool on( point p, line l )
{
if ( l.dx*(p.y-l.y)-l.dy*(p.x-l.x) == 0 )
if ( (p.x-l.x)*(p.x-l.x-l.dx) <= 0 )
if ( (p.y-l.y)*(p.y-l.y-l.dy) <= 0 )
return true;
return false;
}

//点在多边形内
bool in( point p, point* P, int n )
{
double d[4][2] = {-101,-103,-103,101,101,-103,101,103};
for ( int t = 0 ; t < 4 ; ++ t ) {
line s1 = line( p, point( d[t][0], d[t][1] ) );
int  count = 0;
for ( int i = 0 ; i < n ; ++ i ) {
line s2 = line( P[i], P[i+1] );
if ( on( p, s2 ) ) return true;
if ( s_cross_s( s1, s2 ) ) count ++;
if ( on( P[i], s1 ) && l_cross_s( s1, line( P[i+1], P[(i-1+n)%n] ) ) ) count ++;
}
if ( count%2 == 0 ) return false;
}
return true;
}

//两直线交点
point crosspoint( line l, line m )
{
point a = point( m.x, m.y );
point b = point( m.x+m.dx, m.y+m.dy );
if ( m.dx*l.dy == m.dy*l.dx ) {
if ( dist( point( l.x, l.y ), a ) < dist( point( l.x, l.y ), b ) )
return a;
else return b;
}else {
double a1 = -l.dy,b1 = l.dx,c1 = l.dx*l.y-l.dy*l.x;
double a2 = -m.dy,b2 = m.dx,c2 = m.dx*m.y-m.dy*m.x;
double x = (c1*b2-c2*b1)/(a1*b2-a2*b1);
double y = (c1*a2-c2*a1)/(b1*a2-b2*a1);
return point( x, y );
}
}

//计算空的最大长度
double Calcul( int N )
{
H[N] = H[0];

point  X[ 21 ];
double D = 0.0;
for ( int i = 0 ; i < N ; ++ i )
for ( int j = i+1 ; j < N ; ++ j ) {
line l = line( H[i], H[j] );

int S = 0;
for ( int k = 0 ; k < N ; ++ k ) {
line m = line( H[k], H[k+1] );
if ( l_cross_s( l, m ) )
X[S ++] = crosspoint( l, m );
}
X[S ++] = H[i];
X[S ++] = H[j];

P0 = point( -101, -103 );
for ( int k = 0 ; k < S ; ++ k )
X[k].d = dist( P0, X[k] );
sort( X, X+S, cmp2 );

double sum = 0.0;
int    fla = 0;
for ( int i = 1 ; i < S ; ++ i ) {
if ( in( point( (X[i-1].x+X[i].x)/2, (X[i-1].y+X[i].y)/2 ), H, N ) ) {
if ( fla ) sum += dist( X[i-1], X[i] );
else sum = dist( X[i-1], X[i] );
D = max( D, sum );
fla = 1;
}
}
}

return D;
}

int main()
{
int T,N,M;
while ( scanf("%d",&T) != EOF )
while ( T -- ) {
scanf("%d",&N);
for ( int i = 0 ; i < N ; ++ i )
scanf("%lf%lf",&H[i].x,&H[i].y);
scanf("%d",&M);
for ( int i = 0 ; i < M ; ++ i )
scanf("%lf%lf",&C[i].x,&C[i].y);

//计算硬币最小宽度
double d = Graham( M );

//计算空的最大长度
double D = Calcul( N );

if ( d <= D ) printf("legal\n");
else printf("illegal\n");
}
return 0;
}

1. 老实说，这种方法就是穷举，复杂度是2^n，之所以能够AC是应为题目的测试数据有问题，要么数据量很小，要么能够得到k == t，否则即使n = 30，也要很久才能得出结果，本人亲测