bzoj1822: [JSOI2010]Frozen Nova 冷冻波
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
分析
计算几何与网络流的一个小结合,挺有意思的。
首先考虑网络流。对于巫妖的施法时间,肯定是要二分答案的。建图的话就是源点到巫妖,流量为巫妖的施法次数,每个巫妖连到可以杀死的小精灵,小精灵连到汇点容量都是1,判断有没有流满小精灵就可以了。
至于巫妖可否杀死小精灵的判断,就是判断某条线段于圆有没有交点。
那么我们计算线段到圆心最短距离和半径比就可以了。
但是注意是线段不是直径。所以我们首先判断垂直的那个店是否在线段上。
判断方法用余弦定理判断圆心和线段两个端点的夹角是锐角直角还是钝角。如果是钝角的话直接把端点到圆心短的那条和半径比。
否则的话叉积求面积除以底边就是高了,也就是我们要的距离,仍然和半径比。
结束它
没有卡精度,shuffle
代码
/**************************************************************
Problem: 1822
User: 2014lvzelong
Language: C++
Result: Accepted
Time:88 ms
Memory:3944 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int M = 220000, N = 1100, inf = 0x3f3f3f3f;
const double eps = 1e-8;
int read() {
char ch = getchar();int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
struct P {
int x, y;
P(int a = 0, int b = 0) : x(a), y(b) {}
int operator * (P a) {return x * a.y - y * a.x;}
int operator ^ (P a) {return x * a.x + y * a.y;}
P operator - (P a) {return P(x - a.x, y - a.y);}
}L[N], F[N], C[N];
int Lr[N], Cr[N], Ti[N], b1, b2;
int sqr(int a) {return a * a;}
int sqr(P a) {return a ^ a;}
int to[M], nxt[M], w[M], pre[N], h[N], cur[N], gap[N], Q[N], n, m, k, top = 1, s, t;
bool vis[N];
void add(int u, int v, int ww) {to[++top] = v; w[top] = ww; nxt[top] = pre[u]; pre[u] = top;}
void adds(int u, int v, int w) {add(u, v, w); add(v, u, 0);}
bool bfs() {
for(int i = 0;i <= t + 2; ++i) h[i] = -1, gap[i] = 0;
++gap[++h[t]]; int L = 0, R; Q[R = 1] = t;
while(L < R) {
int u = Q[++L];
for(int i = pre[u]; i; i = nxt[i])
if(!(~h[to[i]])) {
++gap[h[to[i]] = h[u] + 1];
Q[++R] = to[i];
}
}
return ~h[s];
}
int dfs(int u, int minf) {
if(u == t) return minf;
int flow = 0, f;
for(int i = cur[u]; i; i = nxt[i])
if(w[i] && h[u] == h[to[i]] + 1) {
f = min(w[i], minf - flow);
f = dfs(to[i], f);
flow += f; w[i] -= f; w[i ^ 1] += f;
if(w[i]) cur[u] = i;
if(minf == flow) return flow;
}
if(!(--gap[h[u]])) h[s] = t + 2;
++gap[++h[u]];
cur[u] = pre[u];
return flow;
}
int sap() {
if(!bfs()) return 0; int ans = 0;
for(int i = 0;i <= t; ++i) cur[i] = pre[i];
while(h[s] < t + 2) ans += dfs(s, inf);
return ans;
}
bool check(int u, int v) {
int a = sqr(L[u] - F[v]);
if(a > Lr[u]) return false;
double d;
for(int i = 1;i <= k; ++i) {
int b = sqr(C[i] - L[u]), c = sqr(C[i] - F[v]);
if(b > c) swap(b, c);
if(a + b < c) d = sqrt(b);
else d = fabs((L[u] - C[i]) * (F[v] - C[i]) * 1.0) / sqrt(a);
if(d < Cr[i]) return false;
}
return true;
}
void Pre() {
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
if(check(i, j)) adds(i, j + n, 1);
b1 = top;
}
void rebuild(int mid) {
for(int i = 2;i <= b1; i += 2) w[i] = 1, w[i + 1] = 0;
for(int i = b1 + 1; i <= b2; i += 2) w[i] = 1, w[i + 1] = 0;
for(int i = 1;i <= n; ++i) w[b2 + (i << 1) - 1] = mid / Ti[i] + 1, w[b2 + (i << 1)] = 0;
}
void binary() {
int L = 0, R = 1e9, ans = -1;
while(L <= R) {
int mid = L + R >> 1;
rebuild(mid);
if(sap() == m) {
ans = mid; R = mid - 1;
}
else L = mid + 1;
}
printf("%d\n", ans);
}
int main() {
n = read(); m = read(); k = read(); s = n + m + 1; t = s + 1;
for(int i = 1;i <= n; ++i) {L[i].x = read(); L[i].y = read(); Lr[i] = sqr(read()); Ti[i] = read();}
for(int i = 1;i <= m; ++i) {F[i].x = read(); F[i].y = read();}
for(int i = 1;i <= k; ++i) {C[i].x = read(); C[i].y = read(); Cr[i] = read();}
Pre();
for(int i = 1;i <= m; ++i) adds(i + n, t, 0);
b2 = top;
for(int i = 1;i <= n; ++i) adds(s, i, 0);
binary();
return 0;
}