您的位置:首页 > 其它

ZOJ3720 Magnet Darts(点在多边形内)

2014-03-31 20:29 155 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5043

Magnet Darts
Time Limit: 2 Seconds      Memory Limit: 65536 KB

There is a magnet board on the wall, and you can throw magnet darts towards it. When a magnet dart hit a point (x, y), because of the magnetism, it will be pulled to the nearest integer
point (x', y'), and you can get a score of Ax' + By'.
To make the game more interesting, only the integer points in the given N-polygon (or on the border) could get score. And we assume all the throw must hit a point which is
in a rectangle area, and the polygon is also in the rectangle. Your task is to calculate the average expectation of score per throw.

Input

There are multiple test cases. For each test case:
The first line contains four real numbers P0, Q0, P1, Q1 (0≤P0<P1≤500,
0≤Q0<Q1≤500), represents the lower left point and the upper right point of the rectangle area, all the throw must hit a point in it.
The second line contains three integers N (3≤N≤20), A, B (-100≤A, B≤100). The meaning of them is in the description above.
Next N lines, each line contains two intergers Xi, Yi, represents the ith vertex of the polygon by clockwise order, we
promise each vertex is in the rectangle area.
There is a blank line between every two cases.

Output

One line for each case. The the average expectation of score per throw with three decimal places.

Sample Input

0 0 4 3
3 1 1
2 3
4 2
3 0

Sample Output

1.333


题意:向一个矩形的靶子上扔飞镖,扔的飞镖会自动移动到距离它最近的整数点上。如果整数点在多边形A内,则能得到A*i+B*j分,求平均每一镖得分的数学期望。

首先要理解,什么叫做移动到最近的整数点上。画图可以发现,对于一个整数点,落在它左0.5,右0.5,上0.5,下0.5组成的正方形区域内的飞镖会被吸引到这个点上来。

由此我们可以推出,靶子上能得分的区域,就是在多边形A内的所有整数点所组成的正方形的面积之和。

得分的概率为正方形面积之和/矩形面积;得的分数期望为对于所有A中的整数点,(A*i+B*j)*该点的正方形面积的和。

所以最终的数学期望为所有A中的整数点,(A*i+B*j)*该点的正方形面积的和/矩形面积。

注意点1:A不一定是凸多边形,所以要用转角法判断点是否在多边形内(关于转角法,代码来自大白书,在下小沙包一只,就不乱解释了)。

注意点2:整点的正方形面积有可能会超出矩形边界,要注意此时它的形状不再是正方形了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
#define eps 1e-8

struct point
{
double x,y;
point(){}
point(double _x,double _y)
{
x=_x;y=_y;
}
point operator - (const point &b) const
{
return point(x-b.x,y-b.y);
}
}pa[50],p,q;

int n,a,b;

int dcmp(double x)
{
return (x>eps)-(x<-eps);
}

double cross(point a,point b)
{
return a.x*b.y-b.x*a.y;
}

double dot(point a,point b)
{
return a.x*b.x+a.y*b.y;
}

bool onseg(point p,point a1,point a2)//判断点是否在线段a1,a2上
{
return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<=0;
}

int inpolygon(point p)//判断点是否在多边形内部
{
int wn=0;
for (int i=0;i<n;i++)
{
if (onseg(p,pa[i],pa[i+1])==1) return 1;
int k=dcmp(cross(pa[i+1]-pa[i],p-pa[i]));
int d1=dcmp(pa[i].y-p.y);
int d2=dcmp(pa[i+1].y-p.y);
if (k>0&&d1<=0&&d2>0) ++wn;
if (k<0&&d2<=0&&d1>0) --wn;
}
if (wn!=0) return 1;
return 0;
}

int main()
{
while (scanf("%lf%lf%lf%lf",&p.x,&p.y,&q.x,&q.y)!=EOF)
{
scanf("%d%d%d",&n,&a,&b);
for (int i=0;i<n;i++)
{
scanf("%lf%lf",&pa[i].x,&pa[i].y);
}
pa
=pa[0];
double ans=0.0;
for (int i=ceil(p.x);i<=(int)q.x;i++)
{
for (int j=ceil(p.y);j<=(int)q.y;j++)
{
if (inpolygon(point(i,j))==0) continue;
double up,down,left,right;//计算出吸引到该点的范围
up=min(j+0.5,q.y);
down=max(j-0.5,p.y);
left=max(i-0.5,p.x);
right=min(i+0.5,q.x);
double area=(up-down)*(right-left);
ans=ans+area*(a*i+b*j);//计算得分概率
}
}
ans=ans/((q.x-p.x)*(q.y-p.y));//除以总面积即为答案
printf("%.3lf\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  zoj 计算几何