这题一开始折磨了我一个上午,下狠心重编,结果一下就过了。看来重编也算是个好方法。
题目大意:在平面上有N个boss,boss始不会动,还有M架小飞机,给出每架小飞机的飞行路线(是线段,飞到终点后消失),还有射程(即一个圆的半径),飞行速度,能量,每攻击boss一个单位的时间就要消耗一个单位的能量(攻击的时间可以是小数),boss不能在同一时刻被多架飞机攻击。求boss被攻击的最大总时间。
首先要知道如何求boss被每架飞机攻击的时间。这里需要求直线和圆的交点(或许会有两个,也可能没有)。
直线方程:ax + by + c = 0:
设飞行路线线段的两个端点的坐标分别为(x1, y1),(x2, y2)。
a = y1 - y2;
b = x2 - x1;
c = x1 * y2 - x2 * y1。
圆的方程 :
设boss的坐标为(p, q),射程为r
(x - p) ^ 2 + (y - q) ^ 2 = r ^ 2
一元二次方程的标准形式为
a' x ^ 2 + b' x + c' = 0,运用公式法 x = ( - b' ± sqrt ( b' ^ 2 - 4 a' c') ) / (2 a')。
为了区分开直线方程的a和一元二次方程的a,一元二次方程的是a'(有一撇‘)。
a' = 1 + (a ^ 2) / (b ^ 2);
b' = - 2 p + 2 a c / (b ^ 2) + 2 a q / b;
c' = - (r ^ 2) + p ^ 2 + q ^ 2 + (c ^ 2) / (b ^ 2) + 2 q c / b。
当b为0时(即x1 = x2)要特别判断一下,这时候x就等于x1,y的值也好求了。
求出了交点,那么攻击的时间也容易求了,然后就是网络流构图。
对于“boss不能在同一时刻被多架飞机攻击”这个条件,正好能解决。
然后做一次小数的网络流就可以了。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
using namespace std;
#define x first
#define y second
typedef pair<double, double> point;
typedef point interval;
const int N = 20, M = 20;
const int FV = 2 + M + 2 * N * M;
const int FE = (M + (M + 1) * 2 * N * M) * 2;
int n, m;
point boss[N], start[M], end[M];
int V[M], R[M], E[M];
void init()
{
scanf("%d%d\n", &n, &m);
for (int i = 0; i < n; i ++)
scanf("%lf%lf\n", &boss[i].x, &boss[i].y);
for (int i = 0; i < m; i ++)
{
scanf("%lf%lf", &start[i].x, &start[i].y);
scanf("%lf%lf", &end[i].x, &end[i].y);
scanf("%d%d%d\n", &V[i], &R[i], &E[i]);
}
}
int source = 0, sink = 1, vc = 2, ec = 0;
int from[FV], to[FE], next[FE];
double cap[FE];
void insert(int u, int v, double c)
{
to[ec] = v;
next[ec] = from[u];
cap[ec] = c;
from[u] = ec ++;
to[ec] = u;
next[ec] = from[v];
cap[ec] = 0e+0;
from[v] = ec ++;
}
int Arrc;
pair<double, int> Arr[2 * N * M];
int plane_cur[M];
set<int> plane_set;
inline double squ(double a)
{
return a * a;
}
inline double dis(point &a, point &b)
{
return sqrt(squ(a.x - b.x) + squ(a.y - b.y));
}
interval calc(point &a, point &b, int V, point p, int R)
{
double linea = a.y - b.y, lineb = b.x - a.x,
linec = a.x * b.y - a.y * b.x;
point c, d;
if (lineb != 0e+0)
{
double equa = 1e+0 + squ(linea) / squ(lineb),
equb = -2e+0 * p.x +
2e+0 * linea * linec / squ(lineb) +
2e+0 * linea * p.y / lineb,
equc = - squ(R) + squ(p.x) + squ(p.y) +
squ(linec) / squ(lineb) +
2e+0 * p.y * linec / lineb;
double t = squ(equb) - 4e+0 * equa * equc;
if (t < 0e+0) return make_pair(0e+0, 0e+0);
t = sqrt(t);
c.x = (- equb - t) / 2e+0 / equa;
d.x = (- equb + t) / 2e+0 / equa;
c.y = (- linea * c.x - linec) / lineb;
d.y = (- linea * d.x - linec) / lineb;
}
else
{
c.x = d.x = a.x;
double t = squ(R) - squ(a.x - p.x);
if (t < 0e+0) return make_pair(0e+0, 0e+0);
t = sqrt(t);
c.y = t + p.y;
d.y = - t + p.y;
}
if ((a < b) != (c < d)) swap(c,d);
if (a < b)
{
c = max(c, a);
d = min(d, b);
if (c > d) return make_pair(0e+0, 0e+0);
}
else
{
c = min(c, a);
d = max(d, b);
if (d > c) return make_pair(0e+0, 0e+0);
}
return make_pair(dis(a, c) / V, dis(a, d) / V);
}
void graph()
{
memset(from, -1, sizeof(from));
for (int i = 0; i < m; i ++)
{
insert(source, vc, E[i]);
plane_cur[i] = vc ++;
}
for (int i = 0; i < n; i ++)
{
Arrc = 0;
for (int j = 0; j < m; j ++)
{
interval t = calc(start[j], end[j], V[j], boss[i], R[j]);
if (t.first != t.second)
{
Arr[Arrc ++] = make_pair(t.first, j);
Arr[Arrc ++] = make_pair(t.second, j);
}
}
sort(Arr, Arr + Arrc);
for (int i = 0; i < Arrc; i ++)
{
set<int>::iterator iter = plane_set.find(Arr[i].second);
if (iter == plane_set.end()) plane_set.insert(Arr[i].second);
else plane_set.erase(iter);
if (i < Arrc - 1)
{
double timer = Arr[i + 1].first - Arr[i].first;
for (iter = plane_set.begin();
iter != plane_set.end(); iter ++)
insert(plane_cur[*iter], vc, timer);
insert(vc ++, sink, timer);
}
}
}
}
queue<int> Q;
int lev[FV];
bool bfs()
{
while (! Q.empty()) Q.pop();
memset(lev, -1, sizeof(lev));
lev[source] = 0;
Q.push(source);
while (! Q.empty())
{
int u = Q.front();
Q.pop();
for (int e = from[u]; e != -1; e = next[e])
{
int v = to[e];
if (cap[e] > 0e+0 && lev[v] == -1)
{
lev[v] = lev[u] + 1;
if (v == sink) return true;
Q.push(v);
}
}
}
return false;
}
double search(int u, double flow)
{
double rest = flow;
if (u == sink) return flow;
for (int e = from[u]; e != -1; e = next[e]) {
int v = to[e];
if (cap[e] > 0e+0 && lev[v] == lev[u] + 1)
{
double t = search(v, min(rest, cap[e]));
if (t > 0e+0)
{
cap[e] -= t;
cap[e ^ 1] += t;
rest -= t;
}
}
}
return flow -= rest;
}
void dinic()
{
double ans = 0e+0;
while (bfs())
{
double t = search(source, 1e+4);
if (t == 0e+0) break;
ans += t;
}
printf("%.6lf\n", ans);
}
int main()
{
freopen("star.in", "r", stdin);
freopen("star.out", "w", stdout);
init();
graph();
dinic();
return 0;
}