P3829 信用卡凸包

这算是凸包模板的拓展吧,其实只要理解了和模板几乎一样呀…
做法:
其实只要把每个做了圆弧处理的长方形把四个四分之一圆去掉,再切成一个长方形,把那4个点加入点集,做一遍凸包,最后加上有个圆的周长就好了QAQ 是不是很简单
上代码

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<string.h>
#include<algorithm>
#define For(i,f,l) int pd=(f<l)*1+(l<=f)*-1;for(i=f;i!=l+pd;i+=pd)
#define pi 3.1415926535//π还是自己写上方向呀
using namespace std;
struct point//定义一个点
{double x,y;};
double sqr(double a)//平方
{return a*a;}
int i,j,k,m,n,h,t;
point Point[100001],check[100001];
bool cmp(point a,point b)//根据坐标排序
{
  if(a.y!=b.y)return a.y>b.y;
  return a.x>b.x;
}
double far(point a,point b)
{return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}//求两点之间的长度
double side(point a,point b,point c)//凸包做法的核心部分,详见凸包模板
{
  return a.x*b.y+a.y*c.x+b.x*c.y-a.x*c.y-a.y*b.x-b.y*c.x;
}
void Around()//凸包做法的核心部分,详见凸包模板
{
  h=n+1;
  t=n+1;
  int i;
  check[t++]=Point[1];
  for(i=1;i<=n;i++)
  {
  	check[t]=Point[i];
  	if(side(check[n],Point[i],Point[i+1]))break;
  }
  if(n<2)return;
  check[++t]=check[--h]=Point[++i];
  if(side(check[n-1],check[n],check[n+1])<0)swap(check[n-1],check[n]);
  for(++i;i<=n;i++)
  {
  	if(side(check[h+1],check[h],Point[i])<0&&side(check[t-1],check[t],Point[i])>0)continue;
    while(t-h>1&&side(check[h+1],check[h],Point[i])>=0)++h;
    check[--h]=Point[i];
    while(t-h>1&&side(check[t-1],check[t],Point[i])<=0)--t;
    check[++t]=Point[i];
  }
}
int main()
{
  cin>>n;
  double a,b,R,X,Y,th;
  cin>>a>>b>>R;
  a-=R*2;//切掉后的边长
  b-=R*2;
  double Long=sqrt(sqr(a)+sqr(b))/2;//算出对角线的一半
  double An[4];//方便计算4个点的坐标
  //这个公式就不一一说明了,自己总可以推出来QAQ
  An[0]=atan(a/b);
  An[1]=pi-An[0];
  An[2]=pi+An[0];
  An[3]=2*pi-An[0];
  double ans=R*2*pi;//现在ans里放一个圆的周长
  for(i=1;i<=n*4;i+=4)
  {
    cin>>X>>Y>>th;
    for(j=0;j<4;j++)
    {//把4个点加入点集
      Point[i+j].x=cos(th+An[j])*Long+X;
      Point[i+j].y=sin(th+An[j])*Long+Y;
    } 
  }
  n=n*4;//点的个数=n*4
  //模板凸包做法
  sort(Point+1,Point+n+1,cmp);
  Around();
  double fX=check[h].x,fY=check[h].y;
  for(i=h;i<t;i++)
  {
  	ans+=far(check[i],check[i+1]);//一条一条边加上
  }
  cout<<fixed<<setprecision(2)<<ans;//输出ans
  return 0;
}

凸包的题都还算比较有难度,还是要思考后在动手QAQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值