Closed Fences

题意:给定平面上的封闭多边形和一个观测点,求这个图形是不是简单多边形(边不相交),如果是简单多边形,求从观测点能够看到的所有边。

解题思路

  1. 确定是不是简单多边形非常简单,检验每条边与其他的边有没有交点即可
  2. 第二个问题略复杂,首先以观测点为原点O,得到多边形每个顶点A的坐标。然后根据这个坐标得到x轴正方向逆时针旋转到与向量OA重合所转过的弧度angle,这个angle的范围为[0, 2pi),将这些点按照弧度升续排列得到集合S
  3. 每次取S中相邻两项i和i+1(S最后一项与第一项相邻),将观测者的视角限定在由这两个点圈定的弧度范围内。求这两个点A, B的中点C,那么与射线OC相交的第一个点所在的边就是能够被看到的。求交点可以用USACO中阅读材料(http://cerberus.delos.com:791/usacotext2?a=cY7GKShmD1w&S=geom)中的“Two line segments intersect”来完成,其中求i, j可以用克拉默法则。求出i, j后,必须要i > 0且0<=j<=1,射线和边才有交点。而与射线OC相交的第一个点对应的i是最小的
  4. 通过3就能得到每一种视角下可看到的边,将其整合起来就能得到最后的答案,输出格式问题就不谈了

代码

/*
ID: zc.rene1
LANG: C
PROG: fence4
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

#define MAX 99999999

int N;
int observer[2];
int corners[200][2];
int corners_in_observer[200][2];
double angle[200];
double pi;
int angle_order[200];
int angle_order_reverse[200];
int angle_color[200];
int ab[2], ac[2], ad[2], ca[2], cb[2], cd[2];
int visible[200];
int total_visible = 0;

int GetDistance(int a[2], int b[2])
{
    int x, y;
    x = a[0] - b[0];
    y = a[1] - b[1];
    return x * x + y * y;
}

int GetCrossProduct(int a[2], int b[2])
{
    return a[0] * b[1] - a[1] * b[0];
}

int IsCross(int a[2], int b[2], int c[2], int d[2])
{
    int m;
    for (m=0; m<2; m++)
    {
	ab[m] = b[m] - a[m];
	ac[m] = c[m] - a[m];
	ad[m] = d[m] - a[m];
	ca[m] = a[m] - c[m];
	cb[m] = b[m] - c[m];
	cd[m] = d[m] - c[m];
    }
    if (GetCrossProduct(ab, ac) * GetCrossProduct(ab, ad) >= 0)
    {
	return 0;
    }
    if (GetCrossProduct(cd, ca) * GetCrossProduct(cd, cb) >= 0)
    {
	return 0;
    }
    return 1;
}

int IsValid(void)
{
    int i, j;
    for (i=0; i<N; i++)
    {
	for (j=0; j<N; j++)
	{
	    if (i != j)
	    {
		if (IsCross(corners[i], corners[(i + 1) % N], corners[j], corners[(j + 1) % N]))
		{
		    return 0;
		}
	    }
	}
    }
    return 1;
}

/*return the angle of vector(a, b) from X-axis, 0~2pi*/
double NewAtan2(int a, int b)
{
    double temp = atan2(b, a);

    if (temp < 0)
    {
	temp += (pi + pi);
    }
    return temp;
}

void SortAngle(void)
{
    double min;
    int i, min_i;
    int has_process = 0;
    
    memset(angle_order, -1, N * sizeof(int));

    while (has_process < N)
    {
	min = 10.0;
	min_i = -1;
	for (i=0; i<N; i++)
	{
	    if (angle_order[i] == -1)
	    {
		if (angle[i] < min)
		{
		    min = angle[i];
		    min_i = i;
		}
	    }
	}
	angle_order[min_i] = has_process;
	angle_order_reverse[has_process] = min_i;
	has_process++;
    }
}

void GetColors(void)
{
    int i, j, index1, index2;
    int color;
    int ax, ay, bx, by, cx, cy, dx, dy;
    int a, b, c, d, e, f;
    int D, Dm, Dn;
    double m, n, min_m;
    int visible_index;
    
    memset(visible, 0, 200*sizeof(int));
    ax = 0;
    ay = 0;
    for (i=0; i<N; i++)
    {
	index1 = angle_order_reverse[i];
	index2 = angle_order_reverse[(i + 1) % N];
	
	if (angle[index1] == angle[index2])
	{
	    continue;
	}

	bx = corners_in_observer[index1][0] + corners_in_observer[index2][0];
	by = corners_in_observer[index1][1] + corners_in_observer[index2][1];

	min_m = MAX;
	visible_index = -1;
	for (j=0; j<N; j++)
	{
	    cx = corners_in_observer[j][0];
	    cy = corners_in_observer[j][1];
	    dx = corners_in_observer[(j+1)%N][0];
	    dy = corners_in_observer[(j+1)%N][1];
	    a = bx - ax;
	    b = cx - dx;
	    c = cx - ax;
	    d = by - ay;
	    e = cy - dy;
	    f = cy - ay;

	    D = a * e - b * d;
	    Dm = c * e - b * f;
	    Dn = a * f - c * d;

	    if (D == 0)
	    {
		continue;
	    }
	    else
	    {
		m = Dm * 1.0 / D;
		n = Dn * 1.0 / D;
		if ((m > 0) && (n >= 0) && (n <= 1))
		{
		    if (m < min_m)
		    {
			min_m = m;
			visible_index = j;
		    }
		}
	    }
	}
	if (visible_index == -1)
	{
	    continue;
	}
	if (visible[visible_index] == 0)
	{
	    visible[visible_index] = 1;
	    total_visible++;
	}
    }
}

int main(void)
{
    FILE *fin, *fout;
    int i;

    fin = fopen("fence4.in", "r");
    fout = fopen("fence4.out", "w");

    /*get the input*/
    fscanf(fin, "%d", &N);
    fscanf(fin, "%d %d", &observer[0], &observer[1]);
    pi = atan2(0, -1);
    for (i=0; i<N; i++)
    {
	fscanf(fin, "%d %d", &corners[i][0], &corners[i][1]);
	corners_in_observer[i][0] = corners[i][0] - observer[0];
	corners_in_observer[i][1] = corners[i][1] - observer[1];
	angle[i] = NewAtan2(corners[i][0] - observer[0], corners[i][1] - observer[1]);
    }
    /*check if valid*/
    if (!IsValid())
    {
	fprintf(fout, "NOFENCE\n");
	return 0;
    }
    /*sort the angle, generate the order of angle*/
    SortAngle();
    /*core algorithm*/
    GetColors();
    /*output the result*/
    fprintf(fout, "%d\n", total_visible);
    for (i=0; i<(N-2); i++)
    {
	if (visible[i] == 1)
	{
	    fprintf(fout, "%d %d %d %d\n", corners[i][0], corners[i][1], corners[i+1][0], corners[i+1][1]);
	}
    }
    if (visible[N-1] == 1)
    {
	    fprintf(fout, "%d %d %d %d\n", corners[0][0], corners[0][1], corners[N-1][0], corners[N-1][1]);
    }
    if (visible[N-2] == 1)
    {
	    fprintf(fout, "%d %d %d %d\n", corners[N-2][0], corners[N-2][1], corners[N-1][0], corners[N-1][1]);
    }
    return 0;
}









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值