FZU 1973 How many stars(2010福州网选题)

恩,好不容易找到这题的。

去年福州网选的时候我还记得,这题是我读的题,然后给GB说的题意,然后GB问询问多少次,我说100W,然后他纠结了,就去搞别的题了,最后这题也没人动。

今年看了看,依旧没啥想法,搜了下,以AC大牛的思路写了下http://hi.baidu.com/aekdycoin/blog/item/e87f5f9653423c6255fb969b.html。

T T。。。

其中,找线段分界线用了上次convex那个题的一个办法,把反正切值都加上2*pi,然后就可以绕一圈了。。

求两条线夹的点有点纠结,因为细节需要考虑很多,我的s[i][j] 存的是,以i为顶点极角排序后第j个点所处的位置。所以求ij 和 ik夹的点的个数时,需要考虑下下标如何减,因为有两种情况,可能一个是下标很大,一个下标很小,而他们中间的点正好是数组的两头,这样的话夹的点应该是n - (s[i][j] - s[i][k]) - 2。

为了解决这个问题,想了好久滴说,我把三角形划分成顺时针和逆时针(按下标的大小,就是从下标小的到大的看是否是顺时针还是逆时针),然后不同的时针方向计算不同。因为我的seg数组表示的是i,j左边点的个数(i<j),所以这样的话会方便很多。

判断顺时针神马的用叉积判断下就好了。


#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>

using namespace std;

const int MAX = 1010;
const double pi = acos(-1.0);
struct point {double x,y;};
struct NODE{ double a;int ind;};
NODE t[MAX*2];
point p[MAX];
int n;
int s[MAX][MAX];
int seg[MAX][MAX]; 
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
bool cmp(NODE a,NODE b)
{
	return a.a < b.a;
}
void init(int n)//任意三点不共线,有这个条件,多好! 
{
	for(int i=0; i<n; i++)
	{
		int cnt = 0;
		for(int k=0; k<n; k++)
			if( i != k )
			{
				t[cnt].ind = k;
				t[cnt++].a = atan2(p[k].y - p[i].y,p[k].x - p[i].x);
			}
		sort(t,t+n-1,cmp);
		for(int k=0; k<n-1; k++)
			s[i][t[k].ind] = k;
		for(int k=0; k<n-1; k++)
		{
			t[n+k-1].a = t[k].a + 2*pi;
			t[n+k-1].ind = t[k].ind;
		}
		int tt = 1;
		for(int k=0; k<n-1; k++)
		{
			while( t[tt].a < t[k].a + pi )
				tt++;
			if( i < t[k].ind )
				seg[i][t[k].ind] = tt - k - 1;
		}
	}
}
bool clockwise(point a,point b,point c)
{
	if( crossProduct(a,b,c) > 0 )
		return true;
	return false;
}
int compute(int a,int b,int c)
{
	double a1 = atan2(p[b].y - p[a].y,p[b].x - p[a].x);
	double a2 = atan2(p[c].y - p[a].y,p[c].x - p[a].x);
	if( a1 <= 0 && a2 >= 0 )
		return n - (s[a][c] - s[a][b]) - 2;
	return s[a][b] - s[a][c] - 1;
}
int compute1(int a,int b,int c)
{
	double a1 = atan2(p[b].y - p[a].y,p[b].x - p[a].x);
	double a2 = atan2(p[c].y - p[a].y,p[c].x - p[a].x);
	if( a1 >= 0 && a2 <= 0 )
		return n - (s[a][b] - s[a][c]) - 2;
	return s[a][c] - s[a][b] - 1;
}
int main()
{
	int ncases,ind = 1,m;
	int pp[4],a,b,c;
	scanf("%d",&ncases);
	
	while( ncases-- )
	{
		scanf("%d",&n);
		for(int i=0; i<n; i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		
		init(n);
		
		scanf("%d",&m);
		printf("Case %d:\n",ind++);
		while( m-- )
		{
			for(int i=0; i<3; i++)
				scanf("%d",&pp[i]);
			sort(pp,pp+3);
			a = pp[0]; b = pp[1]; c = pp[2];
			int A1 = 0,A2 = 0;
			if( clockwise(p[a],p[b],p[c]) )
			{
				A1 += compute(a,b,c); 
				A1 += compute(b,c,a);
				A1 += compute(c,a,b);
				A2 += seg[a][b];
				A2 += seg[b][c];
				A2 += (n - seg[a][c] - 2);
			}
			else
			{
				A1 += compute1(a,b,c);
				A1 += compute1(b,c,a); 
				A1 += compute1(c,a,b);
				A2 += (n - seg[a][b] - 2);
				A2 += (n - seg[b][c] - 2);
				A2 += seg[a][c];
			}
			int ans = A2 + A1 - 2*(n-3);
			printf("%d\n",ans);
		}
	}

return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值