杭州地区赛的遗憾 Rotational Painting

题目其实稍微注意一下就知道怎么搞了。

重心+凸包!

然后枚举相邻凸点就行

 

#include <iostream>
#include <algorithm>
using namespace std;

#define N 50005
/*==================================================*/
| Graham 求凸包 O(N * logN)
| CALL: nr = graham(pnt, int n, res); res[]为凸包点集;
/*==================================================*/
struct point { double x, y; };
bool mult(point sp, point ep, point op){
 return (sp.x - op.x) * (ep.y - op.y)
  >= (ep.x - op.x) * (sp.y - op.y);
}
bool operator < (const point &l, const point &r){
 return l.y < r.y || (l.y == r.y && l.x < r.x);
}

int graham(point pnt[], int n, point res[]){
 int i, len, k = 0, top = 1;
 sort(pnt, pnt + n);
 if (n == 0) return 0; res[0] = pnt[0];
 if (n == 1) return 1; res[1] = pnt[1];
 if (n == 2) return 2; res[2] = pnt[2];
 for (i = 2; i < n; i++) {
  while (top && mult(pnt[i], res[top], res[top-1]))
   top--;
  res[++top] = pnt[i];
 }
 len = top; res[++top] = pnt[n - 2];
 for (i = n - 3; i >= 0; i--) {
  while (top!=len && mult(pnt[i], res[top],
   res[top-1])) top--;
  res[++top] = pnt[i];
 }
 return top;       // 返回凸包中点的个数
}

/*==================================================*/
| 求多边形重心
| INIT: pnt[]已按顺时针(或逆时针)排好序;
| CALL: res = bcenter(pnt, n);
/*==================================================*/

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;
}
point pnt[N],res[N];
point core;
bool gao(int c)
{
 point dir1;
 dir1.x=res[c+1].x-res[c].x;
 dir1.y=res[c+1].y-res[c].y;
 if(dir1.x==0)
 {
  if( (core.y-res[c].y)*(core.y-res[c+1].y) < 0)
   return true;
  return false;
 }
 else if(dir1.y==0)
 {
  if( (core.x-res[c].x)*(core.x-res[c+1].x) < 0)
   return true;
  return false;
 }
 else
 {
  double a=dir1.x,b=dir1.y;
  double k=b/a;
  double cc=res[c].y-k*res[c].x;
  double xx=(a*core.x-b*cc+b*core.y);
   xx/=(a+b*k);
  if( (xx-res[c].x)*(xx-res[c+1].x) < 0)
   return true;
  return false;
 }
}

int main()
{
 int n,i,j;
 
 int T;
 scanf("%d",&T);
 while(T --)
 {
  scanf("%d",&n);
  for(i=0;i<n;i++)
   scanf("%lf%lf",&pnt[i].x,&pnt[i].y);
  core = bcenter(pnt,n);
  //cout<<core.x<<" "<<core.y<<endl;
  n = graham(pnt,n,res);
  res[n]=res[0];
  //for(i=0;i<=n;i++)
  // cout<<res[i].x<<" "<<res[i].y<<endl;
  //printf("%d/n",n);
  int ans=0;
  for(i=0;i<n;i++)
   if(gao(i))
    ans++;
  printf("%d/n",ans);

 }
 return 0;
}

/*
10
4
0 0
1 0
2 2
1 2
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值