ZOJ 3720 Magnet Darts (计算几何,概率,判点是否在多边形内)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3720

题意:

在一个矩形区域投掷飞镖,因此飞镖只会落在整点上,投到每个点的得分是Ax+By。矩形区域里面有个多边形,如果飞镖投在多边形里面则得分,求最终的得分期望。

即:给定一个矩形内的所有整数点,判断这些点是否在一个多边形内

方法:

计算几何的判点是否在多边形内(几何模板),如果在,则令得分加(Ax+By)*以此点为中心边长为1的正方形面积

 1 void solve()
 2 {
 3     double ans = 0;
 4     for (int i = p.x; i <= q.x; i++)
 5     {
 6         for (int j = p.y; j <= q.y; j++)
 7         {
 8             if (PointInPolygon(Point2D(i, j), poly.v, poly.n))
 9                 ans += (a * i + b * j) * (min(i + 0.5, q.x) - max(i - 0.5, p.x)) * (min(j + 0.5, q.y) - max(j - 0.5, p.y));
10         }
11     }
12     printf("%.3f\n", ans / (q.x - p.x) / (q.y - p.y));
13 }

代码:

  1 // #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <set>
  8 #include <list>
  9 #include <map>
 10 #include <iterator>
 11 #include <cstdlib>
 12 #include <vector>
 13 #include <queue>
 14 #include <stack>
 15 #include <algorithm>
 16 #include <functional>
 17 using namespace std;
 18 typedef long long LL;
 19 #define ROUND(x) round(x)
 20 #define FLOOR(x) floor(x)
 21 #define CEIL(x) ceil(x)
 22 const int maxn = 0;
 23 const int maxm = 0;
 24 const int inf = 0x3f3f3f3f;
 25 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL;
 26 // const double INF = 1e30;
 27 // const double eps = 1e-6;
 28 const int P[4] = {0, 0, -1, 1};
 29 const int Q[4] = {1, -1, 0, 0};
 30 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1};
 31 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1};
 32
 33 typedef double db;
 34 const double eps = 1e-7;
 35 const double PI = acos(-1.0);
 36 const double INF = 1e50;
 37
 38 const int POLYGON_MAX_POINT = 1024;
 39
 40 db dmin(db a, db b)
 41 {
 42     return a > b ? b : a;
 43 }
 44 db dmax(db a, db b)
 45 {
 46     return a > b ? a : b;
 47 }
 48 int sgn(db a)
 49 {
 50     return a < -eps ? -1 : a > eps;    //返回double型的符号
 51 }
 52
 53 struct Point2D
 54 {
 55     db x, y;
 56     int id;
 57     Point2D(db _x = 0, db _y = 0): x(_x), y(_y) {}
 58     void input()
 59     {
 60         scanf("%lf%lf" , &x, &y);
 61     }
 62     void output()
 63     {
 64         printf("%.2f %.2f\n" , x, y);
 65     }
 66     //
 67     db len2()
 68     {
 69         return x * x + y * y;
 70     }
 71     //到原点距离
 72     double len()
 73     {
 74         return sqrt(len2());
 75     }
 76     //逆时针转90度
 77     Point2D rotLeft90()
 78     {
 79         return Point2D(-y, x);
 80     }
 81     //顺时针转90度
 82     Point2D rotRight90()
 83     {
 84         return Point2D(y, -x);
 85     }
 86     //绕原点逆时针旋转arc_u
 87     Point2D rot(double arc_u)
 88     {
 89         return Point2D( x * cos(arc_u) - y * sin(arc_u),
 90                         x * sin(arc_u) + y * cos(arc_u) );
 91     }
 92     //绕某点逆时针旋转arc_u
 93     Point2D rotByPoint(Point2D &center, db arc_u)
 94     {
 95         Point2D tmp( x - center.x, y - center.y );
 96         Point2D ans = tmp.rot(arc_u);
 97         ans = ans + center;
 98         return ans;
 99     }
100
101     bool operator == (const Point2D &t) const
102     {
103         return sgn(x - t.x) == 0 && sgn(y - t.y) == 0;
104     }
105     bool operator < (const Point2D &t) const
106     {
107         if ( sgn(x - t.x) == 0 ) return y < t.y;
108         else return x < t.x;
109     }
110     Point2D operator + (const Point2D &t) const
111     {
112         return Point2D(x + t.x, y + t.y);
113     }
114
115     Point2D operator - (const Point2D &t) const
116     {
117         return Point2D(x - t.x, y - t.y);
118     }
119
120     Point2D operator * (const db &t)const
121     {
122         return Point2D( t * x, t * y );
123     }
124
125     Point2D operator / (const db &t) const
126     {
127         return Point2D( x / t, y / t );
128     }
129     //点乘
130     db operator ^ (const Point2D &t) const
131     {
132         return x * t.x + y * t.y;
133     }
134     //叉乘
135     db operator * (const Point2D &t) const
136     {
137         return x * t.y - y * t.x;
138     }
139     //两点之间的角度(-PI , PI]
140     double rotArc(Point2D &t)
141     {
142         double perp_product = rotLeft90()^t;
143         double dot_product = (*this)^t;
144         if ( sgn(perp_product) == 0 && sgn(dot_product) == -1) return PI;
145         return sgn(perp_product) * acos( dot_product / len() / t.len() );
146     }
147     //标准化
148     Point2D normalize()
149     {
150         return Point2D(x / len(), y / len());
151     }
152 };
153
154 struct POLYGON
155 {
156     Point2D v[POLYGON_MAX_POINT];
157     int n;
158 };
159 struct Segment2D
160 {
161     Point2D s , e;
162     Segment2D() {}
163     Segment2D( Point2D _s, Point2D _e ): s(_s), e(_e) {}
164 };
165 //0: 点在多边形外
166 //1: 点在多边形内
167 bool PonSegment2D(Point2D p, Segment2D seg)
168 {
169     return sgn((seg.s - p) * (p - seg.e)) == 0 && sgn((seg.s - p) ^ (p - seg.e)) >= 0;
170 }
171
172 /**** 判断线段在内部相交***/
173 bool SegIntersect2D(Segment2D a, Segment2D b)
174 {
175     //必须在线段内相交
176     int d1 = sgn((a.e - a.s) * (b.s - a.s));
177     int d2 = sgn((a.e - a.s) * (b.e - a.s));
178     int d3 = sgn((b.e - b.s) * (a.s - b.s));
179     int d4 = sgn((b.e - b.s) * (a.e - b.s));
180     if (d1 * d2 < 0 && d3 * d4 < 0) return true;
181     return false;
182 }
183
184 int PointInPolygon(Point2D p, Point2D poly[], int n)
185 {
186     Segment2D l, seg;
187     l.s = p;
188     l.e = p;
189     l.e.x = INF;//作射线
190     int i, cnt = 0;
191     Point2D p1, p2, p3, p4;
192     for (i = 0; i < n; i++)
193     {
194         seg.s = poly[i], seg.e = poly[(i + 1) % n];
195         if (PonSegment2D(p, seg)) return 2; //点在多边形上
196         p1 = seg.s, p2 = seg.e , p3 = poly[(i + 2) % n], p4 = poly[(i + 3) % n];
197         if (SegIntersect2D(l, seg) ||
198                 PonSegment2D(p2, l) && sgn((p2 - p1) * (p - p1))*sgn((p3 - p2) * (p - p2)) > 0 ||
199                 PonSegment2D(p2, l) && PonSegment2D(p3, l) &&
200                 sgn((p2 - p1) * (p - p1))*sgn((p4 - p3) * (p - p3)) > 0 )
201             cnt++;
202     }
203     if (cnt % 2 == 1) return 1; //点在多边形内
204     return 0;//点在多边形外
205 }
206
207 POLYGON poly;
208 Point2D p, q;
209 db a, b;
210 void init()
211 {
212     //
213 }
214 void input()
215 {
216     scanf("%d%lf%lf", &poly.n, &a, &b);
217     for (int i = 0; i < poly.n; i++)
218     {
219         scanf("%lf%lf", &poly.v[i].x, &poly.v[i].y);
220     }
221 }
222 void debug()
223 {
224     //
225 }
226 void solve()
227 {
228     double ans = 0;
229     for (int i = p.x; i <= q.x; i++)
230     {
231         for (int j = p.y; j <= q.y; j++)
232         {
233             if (PointInPolygon(Point2D(i, j), poly.v, poly.n))
234                 ans += (a * i + b * j) * (min(i + 0.5, q.x) - max(i - 0.5, p.x)) * (min(j + 0.5, q.y) - max(j - 0.5, p.y));
235         }
236     }
237     printf("%.3f\n", ans / (q.x - p.x) / (q.y - p.y));
238 }
239 void output()
240 {
241     //
242 }
243 int main()
244 {
245     // std::ios_base::sync_with_stdio(false);
246     // #ifndef ONLINE_JUDGE
247     //     freopen("in.cpp", "r", stdin);
248     // #endif
249
250     while (~scanf("%lf%lf%lf%lf", &p.x, &p.y, &q.x, &q.y))
251     {
252         init();
253         input();
254         solve();
255         output();
256     }
257     return 0;
258 }

ZOJ 3720 Magnet Darts (计算几何,概率,判点是否在多边形内),布布扣,bubuko.com

时间: 2024-10-15 10:29:00

ZOJ 3720 Magnet Darts (计算几何,概率,判点是否在多边形内)的相关文章

zoj 2318 Get Out! 计算几何spfa判负环

题意:给出n个圆心及半径,再给出一个特殊圆心及半径,问这个圆能不能逃出这n个圆的包围 首先先处理一下,将所有圆平移,使特殊圆在原点上,然后其他圆半径加上特殊圆的半径,这样特殊圆就可看成一个点而已,问题变为该点是否可以逃出实际上对于相交的两个圆,我们可以用他们圆心连线来代替它们.这样问题变为是否存在一个多边形,使得原点在这个多边行内部. #include <stdio.h> #include <string.h> #include <algorithm> #include

[ACM] ZOJ 3329 One Person Game (概率DP,有环,巧妙转化)

One Person Game Time Limit: 1 Second      Memory Limit: 32768 KB      Special Judge There is a very simple and interesting one-person game. You have 3 dice, namely Die1, Die2 and Die3. Die1 has K1 faces. Die2 has K2 faces. Die3 has K3 faces. All the

poj 1465 &amp; zoj 1136 Multiple (BFS+余数重判)

Multiple Time Limit: 1000MS   Memory Limit: 32768K Total Submissions: 6177   Accepted: 1346 Description a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the small

ZOJ 1081 Within(点是否在多边形内)| 计算几何

ZOJ 1081 Within 我使用的是"射线法":从该点出发,作一条向左的水平射线,与多边形的边的交点有奇数个则点在多边形内. 需要注意的点: 如果点在多边形的边上特判. 考虑射线与多边形的一个交点是多边形的顶点的情况, 最左边的那个顶点算一个交点,左边第二种的那个顶点算两个交点或不算交点都行(但不能算一个交点). #include <cstdio> #include <cstring> #include <cmath> #include <

zoj 1081 Points Within 判断点是否在任意多边形内(模板)

题目来源: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=81 分析: 从p点出发做平行于x轴的射线 l. 求射线与 多边形 线段的交点数num, 若是偶数 , 该点 在外, 若为奇数, 该点在内. 注意: 两个特判, 1:   一个是 射线 l 与 多边形的边  重合 , 若该p点在 线段上, 返回1, 否则 交点 记为 0 个 2: 一个是 射线与 线段的交点 ,为线段的端点, 则我们 对线段的 较低交点 不计算. 代码

zoj 3640 Help Me Escape (概率dp 递归求期望)

题目链接 Help Me Escape Time Limit: 2 Seconds      Memory Limit: 32768 KB Background     If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at the door. And unto thee shall be his desire, and thou shalt rule over him.  

zoj 3329 One Person Game 概率dp

先吐槽几句真心给数学跪了 题意: 有三个均匀的骰子,分别有k1,k2,k3个面,初始分数是0, 当掷三个骰子的点数分别为a,b,c的时候,分数清零,否则分数加上三个骰子的点数和, 当分数>n的时候结束.求需要掷骰子的次数的期望. 题解: 设 E[i]表示现在分数为i,到结束游戏所要掷骰子的次数的期望值. 显然 E[>n] = 0; E[0]即为所求答案; E[i] = ∑Pk*E[i+k] + P0*E[0] + 1; (Pk表示点数和为k的概率,P0表示分数清零的概率) 由上式发现每个 E[

UVA 12382 Grid of Lamps ZOJ 3732 Graph Reconstruction 可图判定性

Uva 12382 题目链接:点击打开链接 ZOJ 3732题解:点击打开链接 Uva12382 题意: 给定n*m的地板,每个地板上有一盏灯,要么亮要么暗. 下面n个数字表示每行至少亮的灯盏数 下面m个数字表示每列至少亮的灯盏数 求:开始灯都是暗的,最少点亮几盏灯能满足上述条件 思路: 先给行和列大到小排序,然后每次用行减掉列.减完后再排个序即可. 即:实时排序. #include <cstdio> #include <cstring> #include <iostream

ZOJ 3640 Help Me Escape 概率dp

有一个吸血鬼被困了,有n条路可以逃出去,每条路有一个难度c[],他初始的战斗力是f,对于第i条路,若f > c[i]他花t[i]天就能出去,否则,他就停留一天,同时战斗力增加c[i]然后再选一条路走出去,他走每条路的概率是相同的.问他逃出去的天数的期望. 设dp[i]表示在战斗力为i时逃出去的期望值,那么可推出状态方程 dp[i] = 1/n * t[j](c[j] > i),dp[i] = 1/n * (1+dp[ i+c[j] ] )( c[j] <= i). 需要注意的是终态的确定