几何和网络流的结合 战火星空

来源:互联网 发布:js array lastindexof 编辑:程序博客网 时间:2024/05/14 19:54

这题一开始折磨了我一个上午,下狠心重编,结果一下就过了。看来重编也算是个好方法。

题目大意:在平面上有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 secondtypedef 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;}


原创粉丝点击