ZOJ3720 Magnet Darts(点在多边形内)

题目链接: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 P0Q0P1Q1 (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), AB (-100≤AB≤100). The meaning of them is in the description above.

Next N lines, each line contains two intergers XiYi, 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[n]=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;
}


让Kustom成为有史以来最强大的动态壁纸制作者,让你的Android设备看起来独一无二!使用它令人敬畏的WYSIWYG(所见即所得)编辑器来创建您自己的设计并同时显示您需要的任何数据,并且还可以使用精彩的动画!如果您在Android上寻找Rainmeter或Conky,就是这样! 使用Kustom,您可以创建定制的数字和模拟时钟(秒针),动画图案,实时地图背景,材料壁纸,复杂的CPU /内存计,随机更改的图像,滚动图像,陀螺效果等等。想象力是极限。 启动器支持 动画仅适用于完全支持Android标准的启动器,因此例如完全支持Google Now Launcher和Nova Launcher。其他一些人可能有问题,现在唯一已知问题的发射器是GO Launcher(我们无法解决这个问题)。 Smart Launcher 3 v3.26.010破解APK就在这里![最新] OK Launcher Prime - 奥利奥启动器与Android™O 8.0 v2.0破解APK [最新] 你得到: - 一些皮肤开始 - 自定义字体,颜色,大小和效果的文字 - 椭圆形,矩形,弧形,三角形,外形等形状 - 渐变,阴影,平铺和彩色滤镜 - Photoshop / GIMP类似于图层叠加效果(模糊,清晰,xor,差异,饱和度) - 触摸您创建的任何对象上的动作/热 - PNG / JPG / WEBp图像支持 - 基于屏幕位置,触摸,事件等的动画,例如淡入淡出,缩放和滚动... -壁纸运动或物体动画的磁传感器/陀螺仪支持 - 功能,条件和全局变量的复杂编程 - 根据时间,地,天气,任何东西更换壁纸! - 通过HTTP动态下载内容(实时地图,天气等) - 原生音乐实用程序(当前播放的歌曲标题,专辑,封面) - Tasker支持 - 要显示的大量数据(如日期,时间,电池,日历) ,天气,天文(日出,日落),CPU速度,内存,倒计时,WiFi和蜂窝状态,交通信息,下一个警报,位置,移动速度等等)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值