BZOJ2087[Poi2010] Sheep
Description
Lyx的QQ牧场养了很多偶数个的羊,他是Vip,所以牧场是凸多边形(畸形)。现在因为他开挂,受到了惩罚,系统要求他把牧场全部分为三角形(划分线不能在牧场中相交,只能在顶点相交),羊也是有个性的,如果他们在三角形中是单数就会有羊自杀(Lyx的样就是畸形),这让Lyx很难办,于是他向你求助了。
Input
输入:第一行由空格隔开的3个整数n(4<=n<=600),k(2<=k<=20000),m(2<=m<=20000),n表示牧场的顶点数,k表示羊的个数(保证为偶数)。接下来n行为顶点的坐标xi、yi,(-15000<=xi,yi<=15000)由空格隔开,接下来k行为羊的坐标,pi,pj,和xi,yi范围一样但是不会在顶点上,严格在牧场内。
Output
输出:牧场能划分的总方案数被m除的余数。
Sample Input
5 4 10
5 5
3 0
-1 -1
-3 4
1 10
1 0
-1 0
1 6
-2 5
Sample Output
3
Solution:
比较明显是dp吧。其实之前TC上有过一道类似的题,那个比较简单好吧。
首先我们当我们连起一条线,我们可以把偶数之羊分成偶数与偶数,但无论如何也不能把奇数分成偶数与偶数,因此我们判断两点之间能不能连边,只需要判断两边的羊是否都是偶数只。
这里我们就需要将这些点按照一个比较舒服的方式排序(比如说顺时针或者是逆时针)。于是就用到了极角排序。其实看张图就知道这个排序是干什么的了:
当然这个排序可以使用反三角函数 arctan 直接比较,但是精度略微堪忧,因此采用向量的叉积。
向量的叉积:
于是极角排序的代码就可以写出来了。调用 sort(begin,end,cmp) 即可。(now作为基准点)
struct Point{
int x,y;
Point operator -(const Point &a)const{
return (Point){x-a.x,y-a.y};
}
int operator *(const Point &a)const{
return x*a.y-a.x*y;
}
}A[M],now;
bool cmp(Point a,Point b){
return (a-now)*(b-now)<0;
}
注意点:极角排序的点与基准点连线的最大角度不能超过 180∘ ,因为它是基于向量的,也就是相当于说基准点要选在凸包上。
然后对于这道题,就可以用这种方法直接处理出哪两个点之间可以连边,dp方程就显而易见了。
#include
#include
#include
#include
#define M 605
#define N 20005
using namespace std;
struct Point{
int x,y;
Point operator -(const Point &a)const{
return (Point){x-a.x,y-a.y};
}
int operator *(const Point &a)const{
return x*a.y-a.x*y;
}
}Q[M],K[N],now;
bool cmp(Point a,Point b){
return (a-now)*(b-now)<0;
}
int mp[M][M],dp[M][M],m;
int dfs(int L,int R){
int &res=dp[L][R];
if(res!=-1)return res;
res=0;
for(int i=L+1;iif(mp[L][i]&&mp[i][R]){
res=(res+1LL*dfs(L,i)*dfs(i,R))%m;
}
}
return res;
}
int main(){
int n,k;
memset(dp,-1,sizeof(dp));
scanf("%d %d %d",&n,&k,&m);
for(int i=1;i<=n;i++)
scanf("%d %d",&Q[i].x,&Q[i].y);
for(int i=1;i<=k;i++)
scanf("%d %d",&K[i].x,&K[i].y);
now=Q[1];
sort(Q+2,Q+n+1,cmp);
for(int i=1;i<=n;i++){
now=Q[i];
sort(K+1,K+k+1,cmp);
int res=0;
for(int j=i+1;j<=n;j++){
while(res1]-now)*(Q[j]-now)<0)res++;
if(res&1||(K[res+1]-now)*(Q[j]-now)==0)continue;
mp[i][j]=mp[j][i]=true;
}
}
for(int i=1;i1]=1;
printf("%d\n",dfs(1,n));
return 0;
}