恩,好不容易找到这题的。
去年福州网选的时候我还记得,这题是我读的题,然后给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;
}