【题意】给出平面的一系列的点的坐标,求其中组成凸边形的个数。
链接:click here~~
简单的计算几何题,熟悉模板的话,很快就能敲出来,只怪自己这番方面的题练的不够多,磨了一两个小时才A掉,
代码:适合(数据不大的情况下)。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define eps 1e-6
struct xy
{
int x;
int y;
} map[100];
int fun(int a,int b,int c)
{
int t;
t=(map[a].x-map[c].x)*(map[b].y-map[c].y)-(map[b].x-map[c].x)*(map[a].y-map[c].y);
return t;
}
double area(xy a, xy b, xy c)
{
return(fabs((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))/2);
}
bool check(xy a, xy b, xy c,xy d)
{
if(fabs(area(b,c,d)-area(a,b,c)-area(a,c,d)-area(a,b,d))<eps)
return false;
return true;
}
int main()
{
int a,b,t,i,j,n,sb=1;
scanf("%d",&t);
while(t--)
{
int ans=0;
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d %d",&map[i].x,&map[i].y);
}
// for(i=0;i<n;i++)
// if(t>=0)
// {
// ans++;
// }
if(n<4)//注意小于四,直接判断
printf("Case %d: %d", sb, ans);
else
{
for(i = 0; i < n; i++)
for(j = i+1; j < n; j++)
for(a = j+1; a < n; a++)
for(b = a+1; b < n; b++)
if(check(map[i],map[j],map[a],map[b])&&check(map[j],map[i],map[a],map[b])
&&check(map[a],map[i],map[j],map[b])&&check(map[b],map[i],map[j],map[a]))
{
ans++;
}
//printf("%d\n",ans);
}
printf("Case %d: %d\n",sb++,ans);
}
return 0;
}
HDU3629(数据比较大(4~700),还没做,不过当作模板了,用上面方法会超时),链接:
click here~~
http://blog.himdd.com/archives/1162
代码:
//Problem : 3629 ( Convex ) Judge Status : Accepted
//RunId : 4422243 Language : C++ Author : himdd
//Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const double pi = std::acos(-1.0);
struct point {
int x, y;
};
point pt[1500];
double ang[1500];
long long C2(int x) {
return (long long)x * (x - 1) / 2;
}
long long solve(int n) {
int i, j, k, tpl, tpr, tn, tpi;
point tp;
long long ans = 0 ;
for(i = 0; i < n; i ++) {
tp = pt[0];
pt[0] = pt[i];
pt[i] = tp;
for(j = 1; j < n; j ++) {
ang[j] = std::atan2((double)
pt[j].y - pt[0].y, (double)pt[j].x - pt[0].x);
}
std::sort(ang + 1, ang + n);
for(j = 1; j < n; j ++)
ang[n + j - 1] = ang[j] + 2 * pi;
tpi = 1;
for(j = 1; j < n; j ++) {
for(; ang[tpi] < ang[j] + pi; tpi ++);
tpl = tpi - j - 1;
tpr = n - 2 - tpl;
ans += C2(tpl) + C2(tpr) - (long long)tpl * tpr;
}
}
return ans / 4;
}
int main() {
int z, i, n;
::scanf("%d", &z);
while(z --) {
scanf("%d", &n);
for(i = 0; i < n; i ++)
scanf("%d %d", &pt[i].x, &pt[i].y);
printf("%I64d\n", solve(n));
}
}
总结一下常用的几种方法:
(1)叉积&&叉乘(常用):
利用以当前顶点为中心的矢量叉乘或者计算三角形的有符号面积判断多边形的方向以及当前顶点的凹凸性。
假设当前连续的三个顶点分别是P1,P2,P3。计算向量P1P2,P2P3的叉乘,也可以计算三角形P1P2P3的面积,得到的结果如果大于0,则表示P3点在线段P1和P2的左侧,多边形的顶点是逆时针序列。然后依次计算下一个前后所组成向量的叉乘,如果在计算时,出现负值,则此多边形时凹多边形,如果所有顶点计算完毕,其结果都是大于0,则多边形时凸多边形。(2)角度:
判断每个顶点所对应的内角是否小于180度,如果小于180度,则是凸的,如果大于180度,则是凹多边形。
(3)凸包法:
这种方法首先计算这个多边形的凸包,关于凸包的定义在此不再赘述,首先可以肯定的是凸包肯定是一个凸多边形。如果计算出来的凸多边形和原始多边形的点数一样多,那就说明此多边形时凸多边形,否则就是凹多边形。
(4)辛普森面积法利用待判别的顶点以及前后两个顶点所组成的三角形,利用辛普森公式计算其面积,如果此三角形面积与整个多边形面积符号相同,那么这个顶点是凸的;如果此三角形面积与整个多边形面积符号不同,那么这个顶点是凹的,即整个多边形也是凹多边形。
判断给出的点的坐标能否组成一个凸边形,
代码:
链接:hdu 2108 click here
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<dequq>
#include<stack>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{0,-1},{-1,0},{0,1},{1,0}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
struct xy
{
int x;
int y;
} d[1000];
int fun(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=fun(i%n,(i+1)%n,(i+2)%n);
if(t<0)break;
}
if(t>=0)
printf("convex\n");
else
printf("concave\n");
}
return 0;
}