#include<stdio.h>
#include<stdlib.h>
struct xy
{
int x;
int y;
}d[1000];
int g(int a,int b,int c)
{
int t;
//公式:s=(x1-x3)*(y2-y3)-(x2-x3)*(y1-y3)
//当s>0时,p1,p2,p3三个点呈逆时针
//当s<0时,p1,p2,p3三个点呈顺时针
t=(d[a].x-d[c].x)*(d[b].y-d[c].y)-(d[b].x-d[c].x)*(d[a].y-d[c].y);
return t;
}
int main()
{
int i,t,n;
while(scanf("%d",&n),n)
{
for(i=0;i<n;i++)
{
scanf("%d %d",&d[i].x,&d[i].y);
}
for(i=0;i<n;i++)
{
//模n是因为当i=n-1的时候n+1,n+2会超出数据范围,所以从头开始为最后一个点和第一二个点判断直线的走向
t=g(i%n,(i+1)%n,(i+2)%n);
if(t<0)break;
}
if(t>=0)
printf("convex\n");
else
printf("concave\n");
}
return 0;
}
You can Solve a Geometry Problem too
/*
算法简单说明:
首先判断以两条线段为对角线的矩形是否相交,如果不相交两条线段肯定也不相交。
(所谓以a1b2为对角钱的矩形就是以两边长为|a1.x – b2.x|和|a1.y – b2.y|
以及a1b2为对角线的矩形)。
如果相交的话,利用矢量叉乘判断两条线段是否相互跨越,如果相互跨越显然就相交,
反之则不相交。算法不难,但是一些特殊情况需要考虑到,比如两条相段共线且在断点处相交。
/******************************************************** * *
* 返回(P1-P0)*(P2-P0)的叉积。 *
* 若结果为正,则<P0,P1>在<P0,P2>的顺时针方向; *
* 若为0则<P0,P1><P0,P2>共线; *
* 若为负则<P0,P1>在<P0,P2>的在逆时针方向; *
* 可以根据这个函数确定两条线段在交点处的转向, *
* 比如确定p0p1和p1p2在p1处是左转还是右转,只要 *
* 求(p2-p0)*(p1-p0),若<0则左转,>0则右转,=0则 *
* 共线 *
* *
\********************************************************/
#include<stdio.h>
#include<stdlib.h>
typedef struct T
{
double x,y;
} point;
double judge( point p1,point p2, point p )//判断点是否在直线的两边
{
return ( p1.x-p.x )*( p2.y-p.y )-( p2.x-p.x )*( p1.y-p.y );
}
bool on_segments( point p1, point p2, point p )//判断端点是不是在直线上
{
double max=p1.x>p2.x?p1.x:p2.x;//找出直线的左右端点的范围
double min=p1.x<p2.x?p1.x:p2.x;
if( p.x>=min&&p.x<=max ) return true;
else return false;
}
bool segments( point p1,point p2,point q1,point q2 )
{
double d1=judge( p1, p2, q1 );
double d2=judge( p1, p2, q2 );
double d3=judge( q1, q2, p1 );
double d4=judge( q1, q2 ,p2 );
if( d1*d2<0&&d3*d4<0 ) return true;
if( d1==0 && on_segments( p1,p2,q1 ) ) return true;//d为0是平行的情况,这是我们就要考虑是不是端点在直线上
if( d2==0 && on_segments( p1,p2,q2 ) ) return true ;
if( d3==0 && on_segments( q1,q2,p1 ) ) return true;
if( d4==0 && on_segments( q1,q2,p2 ) ) return true;
return false;
}
int main()
{
point start[124],end[124];
int n;
while( scanf("%d",&n),n )
{
int sum=0;
for( int i=1; i<=n; i++ )
{
scanf( "%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y );
}
for( int i=1; i<=n; i++ )
for( int j=i+1; j<=n; j++ )
{
if( segments( start[i],end[i],start[j],end[j] ) )
sum++;
}
printf( "%d\n",sum );
}
return 0;
}
Lifting the Stone
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define MAXN 1000005
struct centre
{
double x , y ;
}point[MAXN];
int cas , n ;
struct centre get_centre()
{
struct centre ctr ;
double area = 0 ;
ctr.x = ctr.y = 0 ;
point[n] = point[0] ;
for ( int i = 0 ; i < n ; ++ i )
{
area +=( ( point[i].x * point[i+1].y - point[i].y * point[i+1].x ) / 2.0 ) ; // 以原点为定点,求三角形面积
ctr.x += ( point[i].x * point[i+1].y - point[i].y * point[i+1].x ) * ( point[i].x + point[i+1].x ) ;
ctr.y += ( point[i].x * point[i+1].y - point[i].y * point[i+1].x ) * ( point[i].y + point[i+1].y ) ;
}
ctr.x /= ( area * 6 ) ;
ctr.y /= ( area * 6 ) ;
return ctr ;
}
int main ()
{
scanf ( "%d" , &cas ) ;
while ( cas -- )
{
scanf ( "%d" , &n ) ;
for ( int i = 0 ; i < n ; ++ i )
scanf ( "%lf%lf" , &point[i].x , &point[i].y ) ;
struct centre ctr = get_centre();
printf ( "%.2lf %.2lf\n" , ctr.x , ctr.y ) ;
}
return 0 ;
}
Surround the Trees
#include<stdio.h>
#include<math.h>
#include<cstdlib>
const int MAXN=109;
const double eps=1e-6;
struct point
{
double x,y;
}p[MAXN],h[MAXN];//p数组用于存所有点,h数组用于存凸包点
double distance(point p1,point p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}// 求两点之间的距离
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));
}//判断sp,ep,op是否满足左转,op是向量起始点,sp与op是两向量另外的端点
int cmp(const void *a,const void *b)
{//按极角排序
point *p1=(point *)a;
point *p2=(point *)b;
double t=multiply(*p2,*p1,p[0]);
if(t>eps)
return 1;
else if(fabs(t)<=eps)
{
if(distance(p[0],*p1)>distance(p[0],*p2))
return 1;
else
return -1;
}
else
return -1;
}
void anglesort(point p[],int n)
{//找到最左下方的点
int i,k=0;
point temp;
for(i=1;i<n;i++)
if(p[i].x<p[k].x||((p[i].x==p[k].x)&&(p[i].y<p[k].y)))
k=i;
temp=p[0],p[0]=p[k],p[k]=temp;
qsort(p+1,n-1,sizeof(point),cmp);//找到左下点后再将左下点作为中心进行极角排序,从第p[1]个元素开始,共n-1个元素
}
void Graham_scan(point p[],point ch[],int n,int &len)
{//建立凸包
int i,top=2;
anglesort(p,n);
if(n<3)
{
for(i=0,len=n;i<n;i++)
ch[i]=p[i];
return;//终止函数
}
ch[0]=p[0],ch[1]=p[1],ch[2]=p[2];
p[n]=p[0];
for(i=3;i<=n;i++)
{
while(multiply(ch[top],p[i],ch[top-1])<=0)
top--;
ch[++top]=p[i];
}
len=top+1;
}
int main()
{
int i,n,len;
while(scanf("%d",&n)!=EOF&&n)
{
for(i=0;i<n;i++)
scanf("%lf %lf",&p[i].x,&p[i].y);
Graham_scan(p,h,n,len);//p为所有的点h为凸包点len为凸包点的个数
double sum=0;
for(i=1;i<len;i++)
{
sum+=distance(h[i],h[i-1]);
}
printf("%.2lf\n",sum);
}
return 0;
}
Pick-up sticks
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct T
{
double x,y;
}point;
point start[200024],end[200024];
inline double judge( point p1,point p2,point p )//判断点是否在直线的两边
{
return ( ( p1.x-p.x )*( p2.y-p.y ) - ( p2.x-p.x )*( p1.y-p.y ) );
}
inline bool on_megment( point p1,point p2,point p )//判断端点是不是在直线上
{
double max=p1.x>p2.x?p1.x:p2.x;//找出直线的左右端点的范围
double min=p1.x<p2.x?p1.x:p2.x;
if( p.x>=min&&p.x<=max )
return true;
else
return false;
}
bool megment( point p1,point p2,point q1,point q2 )
{
double d1=judge( p1,p2,q1 );
double d2=judge( p1,p2,q2 );
double d3=judge( q1,q2,p1 );
double d4=judge( q1,q2,p2 );
if( d1*d2<0&&d3*d4<0 )
return true;//如果都异侧就一定相交
if( d1==0&&on_megment( p1,p2,q1 ) )
return true;//d为0是平行的情况,这是我们就要考虑是不是端点在直线上
if( d2==0&&on_megment( p1,p2,q2 ) )
return true;
if( d3==0&&on_megment( q1,q2,p1 ) )
return true;
if( d4==0&&on_megment( q1,q2,p2 ) )
return true;
return false;
}
int main()
{
int n,hash[100024];
while( scanf( "%d",&n ),n )
{
memset( hash, 0,sizeof( hash ) );
int count=0;
for( int i=1; i<=n; i++ )
scanf( "%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y );
for( int i=1;i<=n; i++ )
for( int j=i+1;j<=n; j++ )
{
if( megment( start[i],end[i],start[j],end[j] ) )
{
hash[i]=1;//记录被覆盖的棍子
count++;
break;
}
}
int sum=0;
count=n-count;
printf( "Top sticks:" );
for( int i=1;i<=n; i++ )
{
if( 0==hash[i] )
{
sum++;
printf( count==sum?" %d.\n":" %d,",i );
}
}
}
return 0;
}
Maple trees
/*
凸包+最小圆覆盖
枚举任意3点找其最小覆盖圆
(当为钝角三角形时不是外接圆,而是以其最长边为直径的圆)。
当为外接圆时,半径公式为r=abc/4s;(推导为如下:
由正弦定理,a/sinA=b/sinB=c/sinC=2R,得sinA=a/(2R),
又三角形面积公式S=(bcsinA)/2,所以S=(abc)/(4R),故R=(abc)/(4S).
*/
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int N = 105;
const double eps = 1e-8;
struct point {
int x;
int y;
}p[N], stack[N];
bool isZero(double x) {
return (x > 0 ? x : -x) < eps;
}
double dis(point A, point B) {
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double crossProd(point A, point B, point C) {
return (B.x-A.x)*(C.y-A.y) - (B.y-A.y)*(C.x-A.x);
}
int cmp(const void *a, const void *b) {
point *c = (point *)a;
point *d = (point *)b;
double k = crossProd(p[0], *c, *d);
if (k<eps || (isZero(k)&&dis(p[0], *c)>dis(p[0], *d))) return 1;
return -1;
}
int Graham(int n) {
int x = p[0].x;
int y = p[0].y;
int mi = 0;
for (int i=1; i<n; ++i) {
if (p[i].x<x || (p[i].x==x&&p[i].y<y)) {
x = p[i].x;
y = p[i].y;
mi = i;
}
}
point tmp = p[mi];
p[mi] = p[0];
p[0] = tmp;
qsort(p+1, n-1, sizeof(point), cmp);
p[n] = p[0];
for (int i=0; i<3; ++i) stack[i] = p[i];
int top = 2;
for (int i=3; i<n; ++i) {
if (crossProd(stack[top-1], stack[top], p[i])<=eps && top>=2) --top;
stack[++top] = p[i];
}
return top;
}
double max(double a, double b) {
return a > b ? a : b;
}
int main() {
int n;
while (scanf("%d", &n), n) {
for (int i=0; i<n; ++i) scanf ("%d%d", &p[i].x, &p[i].y);
if (n == 1) printf ("0.50\n");
else if (n == 2) printf ("%.2lf\n", dis(p[0], p[1])*0.50+0.50);
else {
int top = Graham(n);
double maxr = -1;
double a, b, c, r, s;
for (int i=0; i<top; ++i) {//枚举凸包上的点
for (int j=i+1; j<top; ++j) {
for (int k=j+1; k<=top; ++k) {
a = dis(stack[i], stack[j]);
b = dis(stack[i], stack[k]);
c = dis(stack[j], stack[k]);
if (a*a+b*b<c*c || a*a+c*c<b*b || b*b+c*c<a*a) r = max(max(a, b), c) / 2.0;//钝角
else {
s = fabs(crossProd(stack[i], stack[j], stack[k])) / 2.0;
r = a * b * c / (s * 4.0);//三角形外接圆公式
}
if (maxr < r) maxr = r;
}
}
}
printf ("%.2lf\n", maxr+0.5);
}
}
return 0;
}
最大三角形
/*
* 题目要求:求三角形的最大面积
* 方法:凸包+枚举凸包上的点
*/
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int N = 50005;
const double eps = 1e-8;
struct point {
int x;
int y;
}p[N], stack[N];
bool isZero(double x) {
return (x > 0 ? x : -x) < eps;
}
double dis(point A, point B) {
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
int crossProd(point A, point B, point C) {
return (B.x-A.x)*(C.y-A.y) - (B.y-A.y)*(C.x-A.x);
}
int cmp(const void *a, const void *b) {
point *c = (point *)a;
point *d = (point *)b;
double k = crossProd(p[0], *c, *d);
if (k<eps || (isZero(k)&&dis(p[0], *c)>dis(p[0], *d))) return 1;
return -1;
}
int Graham(int n) {
int x = p[0].x;
int y = p[0].y;
int mi = 0;
for (int i=1; i<n; ++i) {
if (p[i].x<x || (p[i].x==x&&p[i].y<y)) {
x = p[i].x;
y = p[i].y;
mi = i;
}
}
point tmp = p[mi];
p[mi] = p[0];
p[0] = tmp;
qsort(p+1, n-1, sizeof(point), cmp);
p[n] = p[0];
for (int i=0; i<3; ++i) stack[i] = p[i];
int top = 2;
for (int i=3; i<n; ++i) {
while (crossProd(stack[top-1], stack[top], p[i])<=eps && top>=2) --top;
stack[++top] = p[i];
}
return top;
}
double maxTrangle(int n) {
int top = Graham(n);
double area, maxArea = 0;
for (int i=0; i<top; ++i) {
for (int j=i+1; j<top; ++j) {
for (int k=j+1; k<=top; ++k) {
area = crossProd(stack[i], stack[j], stack[k]);
if (maxArea < area) maxArea = area;
}
}
}
return maxArea * 0.5;
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i=0; i<n; ++i) scanf ("%d%d", &p[i].x, &p[i].y);
double ans = maxTrangle(n);
printf ("%.2lf\n", ans);
}
return 0;
}
Assignments
/*
思路:贪心,a中最小的与b中最大的组合,即一个升序,一个降序排列即可。
因为假设(a0,b0),(a1,b1)两组数,
a0>a1&&b0>b1则很明显max(a0+b0-t,0)+max(a1+b1-t,0)>=max(a0+b1-t,0)+max(a1+b0-t,0)。。
即(a1,b0),(a0,b1)比(a0,b0),(a1,b1)组合更好。
就上面的证明:假设a1+b1>=t; 则前面等于a0+b0+a1+b1-2t,后面也是。
假设a1+b1<t,且其它都为正,前面等于a0+b0-t。
后面a0+b0+a1+b1-2t==a0+b0-t+负数明显小于前者。
其它有为负数的就不用说了。。。
*/
#include <iostream>
#include<algorithm>
using namespace std;
int cmp(int a,int b)
{
return a>b;
}
int main()
{
int i,n,t,sum;
int a[1010],b[1010];
while(cin>>n>>t)
{
sum=0;
for(i=0;i<n;i++)
cin>>a[i];
for(i=0;i<n;i++)
cin>>b[i];
sort(a,a+n);
sort(b,b+n,cmp);
for(i=0;i<n;i++)
{
if(a[i]+b[i]>t)
sum+=(a[i]+b[i]-t);
}
cout<<sum<<endl;
}
}