凸包求法

 


#include <iostream>
#include <cmath>

using namespace std;

struct POINT
{
 int x, y;
 int flag; // 表示是否在连线内部,在为0
};

POINT list[500], pk;

int stack[500], top, k, rightnum;

void swap(POINT &a, POINT &b)
{
 POINT t;
 t = a;
 a = b;
 b = t;
}

int CrossProd(POINT p0, POINT p1, POINT p2)
{
 return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

int comp(const void *pp1, const void *pp2)
{
 //int t;
 POINT *p1 = (POINT*)pp1, *p2 = (POINT*)pp2;
 return CrossProd(list[0], *p1, *p2)*(-1);
}

void select(int n, int &num)
{
 POINT p1, p2;
 int t, i, j, f;
 for (i = 1; i < n; i++)
 {
  f = 0;
  p1 = list[i];
  if (p1.flag)
  {
   for (j = i + 1; j < n; j++)
   {
    p2 = list[j];
    if (p2.flag)
    {
     t = CrossProd(list[0], p1, p2);
     if (t == 0)
     {
      if ((p1.x - list[0].x) * (p1.x - list[0].x) + (p1.y - list[0].y) *(p1.y - list[0].y) \
       < (p2.x - list[0].x) * (p2.x - list[0].x) + (p2.y - list[0].y) *(p2.y - list[0].y))
      {
       list[i].flag = 0;
      }
      else list[j].flag = 0;
     }
    }
   }
  }
 }
 i = 1;
 for (j = 1; j < n; j++)
 {
  if (list[j].flag == 1)
  {
   list[i] = list[j];
   i++;
  }
 }
 num = i - 1;
 qsort(list + 1, num, sizeof(POINT), comp);
}

int init(int n)
{
 int i, num;
 for (i = 0; i < n; i++)
 {
  cin >> list[i].x >> list[i].y;
  list[i].flag = 1;
  if ((list[i].y < list[0].y) || (list[i].y == list[0].y) && (list[i].x < list[0].x))
  {
   swap(list[0], list[i]);
  }
 }
 select(n, num);
 return num + 1;
}

void graham(int n)
{
 int i;
 if (n == 1) cout << "(" << list[0].x << ", " << list[0].y << ")" << endl;
 if (n == 2) cout << "(" << list[0].x << ", " << list[0].y << ")" \
  "(" << list[1].x << ", " << list[1].y << ")" << endl;
 if (n > 2)
 {
  for (i = 0; i <= 2; i++) stack[i] = i;
  top = 2;
  for (i = 3; i <= n-1; i++)
  {
   while (CrossProd(list[stack[top-1]], list[stack[top]], list[i]) <= 0)
    top--;
   top++;
   stack[top] = i;
  }
  for (i = 0; i <= top; i++) cout << "(" << list[stack[i]].x << ", " << list[stack[i]].y << ")";
  cout << endl;
 }
}

void Chain(int n, int LR) // LR=1生成右链,LR=0生成左链
{
 int m = 0, i, t;
 POINT pm;
 stack[0] = 0;
 top = 0;
 while (m != k)
 {
  pm = pk;
  m = k;
  for (i = 1; i < n; i++)
  {
   t = CrossProd(list[stack[top]], list[i], pm);
   if ((t > 0 && LR==1) || (t < 0 && LR == 0) ||\
    (t == 0) && ((list[i].x - list[stack[top]].x) * (list[i].x - list[stack[top]].x) \
    + (list[i].y - list[stack[top]].y)*(list[i].y - list[stack[top]].y)
    > (pm.x - list[stack[top]].x) * (pm.x - list[stack[top]].x) \
    + (pm.y - list[stack[top]].y) * (pm.y - list[stack[top]].y)))
   {
    pm = list[i];
    m = i;
   }
  }
  top ++;
  stack[top] = m;
 }
 if (LR == 1)
 {
  for (i = 0; i <= top; i++)
  {
   cout << "(" <<list[stack[i]].x << ", " << list[stack[i]].y << ")";
  }
 }
 else
 {
  for (i = top - 1; i > 0; i--)
  {
   cout << "(" <<list[stack[i]].x << ", " << list[stack[i]].y << ")";
  }
  cout << endl;
 }
}

void init2(int n)
{
 int i;
 for (i = 0; i < n; i++)
 {
  cin >> list[i].x >> list[i].y;
  if (i == 0)
  {
   pk = list[0];
   k = 0;
  }
  if ((list[i].y < list[0].y) || (list[i].y == list[0].y) && (list[i].x < list[0].x))
   swap(list[0], list[i]);
  if ((list[i].y > pk.y) || (list[i].y == pk.y) && (list[i].x > pk.x))
  {
   pk = list[i];
   k = i;
  }
 }
}

void Jarvis(int n)
{
 if (n == 1) cout << "(" << list[0].x << ", " << list[0].y << ")" << endl;
 if (n == 2) cout << "(" << list[0].x << ", " << list[0].y << ")" \
  "(" << list[1].x << ", " << list[1].y << ")" << endl;
 if (n > 2)
 {
  Chain(n, 1);
  Chain(n, 0);
 }
}

int main()
{
 int count = 0, n, num;
 while (cin >> n)
 {
  if (n == 0) break;
  count++;
  cout << "set" << count << ":\n";
  cout << "graham...(\n)";
  num = init(n);
  graham(num);
  cout << "Jarvis...(\n)";
  init2(n);
  Jarvis(n);
 }
 return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值