BZOJ1822 Frozen Nova 冷冻波

1822: [JSOI2010]Frozen Nova 冷冻波

Time Limit: 10 Sec  Memory Limit: 64 MB

Description

WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。 在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。 现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?

Input

输入文件第一行包含三个整数N、M、K(N,M,K<=200),分别代表巫妖的数量、小精灵的数量和树木的数量。 接下来N行,每行包含四个整数x, y, r, t,分别代表了每个巫妖的坐标、攻击范围和施法间隔(单位为秒)。 再接下来M行,每行两个整数x, y,分别代表了每个小精灵的坐标。 再接下来K行,每行三个整数x, y, r,分别代表了每个树木的坐标。 输入数据中所有坐标范围绝对值不超过10000,半径和施法间隔不超过20000。

Output

输出一行,为消灭所有小精灵的最短时间(以秒计算)。如果永远无法消灭所有的小精灵,则输出-1。

Sample Input

2 3 1
-100 0 100 3
100 0 100 5
-100 -10
100 10
110 11
5 5 10

Sample Output

5

Source

JSOI2010第二轮Contest1


题解

网络流 + 二分答案 + 计算几何

计算几何用点积和叉积计算点到线段距离,二分所需时间,网络流验证是否可行

大水题,数据有点坑qwq

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 template <class _T> inline void read(_T &_x) {
  4     int _t; bool flag = false;
  5     while ((_t = getchar()) != ‘-‘ && (_t < ‘0‘ || _t > ‘9‘)) ;
  6     if (_t == ‘-‘) _t = getchar(), flag = true; _x = _t - ‘0‘;
  7     while ((_t = getchar()) >= ‘0‘ && _t <= ‘9‘) _x = _x * 10 + _t - ‘0‘;
  8     if (flag) _x = -_x;
  9 }
 10 typedef long long LL;
 11 const int maxn = 1010;
 12 const int maxm = 100010;
 13 const double eps = 1e-8;
 14 inline int sign(double val) {return val < -eps ? -1 : val > eps; }
 15 struct Point {
 16     double x, y;
 17     Point (double a = 0, double b = 0):x(a), y(b) {}
 18 }A[maxn], B[maxn], C[maxn];
 19 double rA[maxn], rC[maxn];
 20 double dot(Point a, Point b, Point c) {
 21     return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
 22 }
 23 double cross(Point a, Point b, Point c) {
 24     return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
 25 }
 26 double dist(Point a, Point b) {
 27     return hypot(a.x - b.x, a.y - b.y);
 28 }
 29 double ldis(Point a, Point b, Point c) {
 30     if (dot(c, a, b) > 0) return min(dist(a, c), dist(b, c));
 31     return fabs(cross(a, b, c) / dist(a, b));
 32 }
 33 bool check(Point a, Point b, Point c, int pc) {
 34     double dis = dist(a, b), r = dot(a, b, c) / dis;
 35     if (r < 0 || r > dis) return true;
 36     return sign(fabs(cross(a, b, c) / r) - rC[pc]) > 0;
 37 }
 38 struct Edge {
 39     int v, flow, nxt;
 40     Edge () {}
 41     Edge (int a, int b, int c):v(a), flow(b), nxt(c) {}
 42 }e[maxm];
 43 int n, m, k, t[maxn], sink;
 44 int fir[maxn], tag[maxn], cur[maxn], ecnt;
 45 bool can[maxn][maxn];
 46 inline void addedge (int a, int b, int c) {
 47     e[++ecnt] = Edge (b, c, fir[a]), fir[a] = ecnt;
 48     e[++ecnt] = Edge (a, 0, fir[b]), fir[b] = ecnt;
 49 }
 50 inline bool bfs() {
 51     memset(tag, 0, sizeof (int) * (sink + 1));
 52     queue<int> q; q.push(0), tag[0] = 1;
 53     while (!q.empty()) {
 54         int now = q.front(); q.pop();
 55         for (int u = fir[now]; u; u = e[u].nxt) {
 56             if (e[u].flow && !tag[e[u].v]) {
 57                 tag[e[u].v] = tag[now] + 1;
 58                 q.push(e[u].v);
 59             }
 60         }
 61     }
 62     return tag[sink] != 0;
 63 }
 64 int dfs(int now, int flow) {
 65     if (now == sink) return flow;
 66     int usd = 0;
 67     for (int &u = cur[now]; u; u = e[u].nxt) {
 68         if (e[u].flow && tag[e[u].v] > tag[now]) {
 69             int ret = dfs(e[u].v, min(e[u].flow, flow - usd));
 70             if (ret) {
 71                 e[u].flow -= ret;
 72                 e[u ^ 1].flow += ret;
 73                 usd += ret;
 74                 if (usd == flow) return flow;
 75             }
 76         }
 77     }
 78     return usd;
 79 }
 80 inline int dinic() {
 81     int flow = 0;
 82     while (bfs()) {
 83         for (int i = 0; i <= sink; ++i) cur[i] = fir[i];
 84         flow += dfs(0, m);
 85     }
 86     return flow;
 87 }
 88 bool check(int tim) {
 89     memset(fir, 0, sizeof (int) * (sink + 1));
 90     ecnt = 1;
 91     for (int i = 1; i <= n; ++i) {
 92         addedge(0, i, tim / t[i] + 1);
 93         for (int j = 1; j <= m; ++j) if (can[i][j]) {
 94             addedge(i, n + j, 1);
 95         }
 96     }
 97     for (int i = 1; i <= m; ++i) addedge(n + i, sink, 1);
 98     return dinic() >= m;
 99 }
100 int main() {
101     //freopen(".in", "r", stdin);
102     //freopen(".out", "w", stdout);
103     read(n), read(m), read(k);
104     for (int i = 1; i <= n; ++i) {
105         scanf("%lf%lf%lf%d", &A[i].x, &A[i].y, &rA[i], &t[i]);
106     }
107     for (int i = 1; i <= m; ++i) {
108         scanf("%lf%lf", &B[i].x, &B[i].y);
109     }
110     for (int i = 1; i <= k; ++i) {
111         scanf("%lf%lf%lf", &C[i].x, &C[i].y, &rC[i]);
112     }
113     for (int i = 1; i <= n; ++i) {
114         for (int j = 1; j <= m; ++j) {
115             bool flag = true;
116             double dis = dist(A[i], B[j]);
117             if (dis > rA[i]) continue;
118             for (int x = 1; x <= k; ++x) {
119                 if (ldis(A[i], B[j], C[x]) < rC[x]) {
120                     flag = false;
121                     break;
122                 }
123             }
124             if (flag) can[i][j] = true;
125         }
126     }
127     for (int i = 1; i <= m; ++i) {
128         bool flag = false;
129         for (int j = 1; j <= n; ++j) if (can[j][i]) {
130             flag = true; break;
131         }
132         if (!flag) {
133             puts("-1");
134             return 0;
135         }
136     }
137     sink = n + m + 1;
138     int l = 0, r = 20000 * m, mid;
139     while (l < r) {
140         if (check(mid = (l + r) >> 1)) r = mid;
141         else l = mid + 1;
142     }
143     cout << l << endl;
144     return 0;
145 }

时间: 2024-10-18 09:27:50

BZOJ1822 Frozen Nova 冷冻波的相关文章

[JSOI2010][BZOJ1822] Frozen Nova 冷冻波

1822: [JSOI2010]Frozen Nova 冷冻波 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1147  Solved: 344[Submit][Status][Discuss] Description WJJ喜欢“魔兽争霸”这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被

bzoj1822: [JSOI2010]Frozen Nova 冷冻波

1822: [JSOI2010]Frozen Nova 冷冻波 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1640  Solved: 516[Submit][Status][Discuss] Description WJJ喜欢"魔兽争霸"这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的

BZOJ 1822 Frozen Nova 冷冻波(最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1822 题意:WJJ喜欢“魔兽争霸”这个游戏.在 游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以 瞬间杀灭一个小精灵. 在森林里有N个巫妖,每个巫妖释放Froz

bzoj 1822: [JSOI2010]Frozen Nova 冷冻波 题解

[原题] 1822: [JSOI2010]Frozen Nova 冷冻波 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 796  Solved: 218 [Submit][Status] Description WJJ喜欢"魔兽争霸"这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没

【bzoj1822】[JSOI2010]Frozen Nova 冷冻波 计算几何+二分+网络流最大流

题目描述 WJJ喜欢“魔兽争霸”这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵. 在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放.不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以

【计算几何】【二分答案】【最大流】bzoj1822 [JSOI2010]Frozen Nova 冷冻波

用三角形面积什么的算算点到直线的距离之类……其实相切的情况是可行的……剩下的就跟某SDOI2015一样了. #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define N 201 #define EPS 0.000001 #define INF 2147483647 struc

【BZOJ1822】【JSOI2010】Frozen Nova 冷冻波

题解:二分答案,然后网络流check. 注意: 理论上来讲,因为如果有 ----------- /             \ /                \ 巫妖----小精灵----------------树桩------- \                  / \                / \----------- / 这种情况,直接用点到直线距离公式是会错误判断的. 但是读者们请用点到直线距离公式吧. 因为数据貌似是这样的. 不妨把巫妖的目光看成能穿透小精灵吧~(至于能

BZOJ 1822 JSOI 2010 Frozen Nova 冷冻波 二分+网络流

题目大意:在平面中有一些巫妖和一些小精灵,还有一些树会阻挡巫妖的视线.每一个巫妖都有一个攻击半径,如果一个小精灵在巫妖的攻击半径内,两点之间的连线没有树木阻挡,那么巫妖就可以秒杀小精灵.每个巫妖都有技能的CD.问最快多长时间可以使小精灵全灭. 思路:看出范围知算法系列.很明显的二分+最大流.二分最短时间,在这个时间内,每个巫妖可以发招time / CD + 1次.那么每次建图就从S到每个巫妖连能够输出的次数流量的边.每个巫妖向能攻击到的小精灵连边,之后每个小精灵向T连边.每次判断max_flow

BZOJ 1822[JSOI2010]Frozen Nova 冷冻波

网络流+二分. n^3枚举判断每个巫妖可以攻击的精灵,向其连1的边,每个精灵向汇点连1的边. 二分答案,修改源点流向每个巫妖的cap,跑最大流看是否等于精灵数. 恩,看起来没什么毛病. 然后狂WA不止.调了一晚上.拍了大半晚上,发现网上找的拿来拍的程序是个WA的...我还能说些什么呢.. 这时候才发现我应该算点到线段的距离而不是直线.保持微笑. 原来这题还有一个计算几何的tag? 算点到直线的距离d,点到线段两点的距离,短的为l,长的为r. 勾股定理算出tmp=sqrt(r*r-d*d);若是t