USACO 3.4.1

      自己不太会计算几何,借鉴了一下别人的方法,

     1.判断多边形是否合法

         任两条边都不相交即合法,注意这里的相交是严格相交,顶点相交不算相交。

     2.能看到哪些边

         扫描线处理

#include<fstream>
#include<string.h>
#include<cmath>
using namespace std;
ifstream fin("fence4.in");
ofstream fout("fence4.out");
const int MAX = 202;
struct point
{
 double x,y;
};
struct edge
{
 point* v[2];
};
point watcher,*vert[MAX];
int n;
edge* fence[MAX];
bool isSight[MAX];
double times(double x1,double y1,double x2,double y2)
{//求叉积
 return x1*y2-x2*y1;
}
void creatEdge()
{
 for(int i=0; i<n-1; i++)
 {
  fence[i] = new edge();
  fence[i]->v[0] = vert[i];
  fence[i]->v[1] = vert[i+1];
 }
 fence[n-1] = new edge();
 fence[n-1]->v[0] = vert[0];
 fence[n-1]->v[1] = vert[n-1];
}
bool isCross(edge*a ,edge*b)
{
 point*s = a->v[0];
 if(times(a->v[1]->x - s->x,a->v[1]->y - s->y,b->v[0]->x - s->x,b->v[0]->y - s->y)
  *times(a->v[1]->x - s->x,a->v[1]->y - s->y,b->v[1]->x - s->x,b->v[1]->y - s->y)>=0)
  return false;
 s = b->v[0];
 if(times(b->v[1]->x - s->x,b->v[1]->y - s->y,a->v[0]->x - s->x,a->v[0]->y - s->y)
  *times(b->v[1]->x - s->x,b->v[1]->y - s->y,a->v[1]->x - s->x,a->v[1]->y - s->y))
  return false;
}
void checkCross()
{
 for(int i=0;i<n;i++)
  for(int j=0;j<n;j++)
  {
   if(i==j)continue;
   if(!isCross(fence[i],fence[j]))continue;
   fout<<"NOFENCE"<<endl;
   exit(0);
  }
}
/*
给定一个射线OA(向量OA与x轴正方向的夹角),算法将记录下边集中与射线OA有交点且交点离O点最近的线段。
*/

void checkLine(double angle)
{
 double min_k = 1E16;
 long firstCrah = -1;
 double lx = cos(angle);
 double ly = sin(angle);
 double k1,t;
 for(int i=0;i<n;i++)
 {
  double& x = watcher.x;
  double& y = watcher.y;
  double& x1 = fence[i]->v[0]->x;
  double& y1 = fence[i]->v[0]->y;
  double& x2 = fence[i]->v[1]->x;
  double& y2 = fence[i]->v[1]->y;
  if(times(x1-x,y1-y,lx,ly)*times(x2-x,y2-y,lx,ly)>=0)//不相交,继续
   continue;
  lx = cos(angle);
  ly = sin(angle);
  if(x2-x1==0)
  {
   k1 = (x1-x)/lx;
  }
  else
  {
   t=(y2-y1)/(x2-x1);
   k1 = (t*(x1-x)+y-y1)/(t*lx-ly);
  }
  if(k1>0 && k1<min_k)
  {
   min_k = k1;
   firstCrah = i;
  }
 }
  if(firstCrah != -1)
  {
   isSight[firstCrah] = true;
  }
}
/*
枚举观察点到每个顶点的向量,然后把其与x轴的夹角(+-)1E-8 rad 后检查沿该方向能看到的fence
*/

void canSight()
{
 memset(isSight,0,sizeof(isSight));
 double angle;
 for(int i=0;i<n;i++)
 {
  angle = atan2(vert[i]->y - watcher.y,vert[i]->x - watcher.x);
  checkLine(angle+1E-8);
  checkLine(angle-1E-8);
 }
}
int main()
{
 fin>>n;
 fin>>watcher.x>>watcher.y;
 for(int i=0;i<n;i++)
 {
  vert[i] = new point();
  fin>>vert[i]->x;
  fin>>vert[i]->y;
 }
 creatEdge();
 checkCross();
 canSight();
 int conter = 0;
 for(int i=0;i<n;i++)
  conter+=isSight[i];
 fout<<conter<<endl;
 for(int i=0;i<n-2;i++)
  if(isSight[i])
   fout<<fence[i]->v[0]->x<<" "
    <<fence[i]->v[0]->y<<" "
    <<fence[i]->v[1]->x<<" "
    <<fence[i]->v[1]->y<<endl;
 if(isSight[n-1])
  fout<<fence[n-1]->v[0]->x<<" "
   <<fence[n-1]->v[0]->y<<" "
   <<fence[n-1]->v[1]->x<<" "
   <<fence[n-1]->v[1]->y<<endl;
 if(isSight[n-2])
  fout<<fence[n-2]->v[0]->x<<" "
   <<fence[n-2]->v[0]->y<<" "
   <<fence[n-2]->v[1]->x<<" "
   <<fence[n-2]->v[1]->y<<endl;
 return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值