OJ-Problems-Source/QUSTOJ/1311_蜘蛛侠.cpp

202 lines
5.4 KiB
C++
Raw Normal View History

/*
* : + , .
* 1. .
* 2. lich和每个wisp分别用一个点来表示.
* 3. i个lich能攻击到第j个wisp, lich[i]wisp[j], 1, 0.
* 4. wisp连一条边到汇点, 1, 0.
* 5. lich连k条边, k为每个lich能攻击到的wisp数量, 1, i条边的费用为i * t (i为0 - k-1, t为lich的cooldown时间)
* , lich满流的边, .
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <math.h>
using namespace std;
const int maxn = 205;
const double eps = 1e-8;
typedef int typef;
typedef int typec;
#define inff 0x0fffffff
#define infc 0x0fffffff
#define V 500
#define E 200000
struct network
{
int nv, ne, pnt[E], nxt[E];
int vis[V], que[V], head[V], pv[V], pe[V];
typef flow, cap[E]; typec cost, dis[E], d[V];
void addedge(int u, int v, typef c, typec w)
{
pnt[ne] = v; cap[ne] = c;
dis[ne] = w; nxt[ne] = head[u]; head[u] = ne++;
pnt[ne] = u; cap[ne] = 0;
dis[ne] = -w; nxt[ne] = head[v]; head[v] = ne++;
}
int mincost(int src, int sink)
{
int i, k, f, r; typef mxf;
for(flow = 0, cost = 0; ; )
{
memset(pv, -1, sizeof(pv));
memset(vis, 0, sizeof(vis));
for(i = 0; i < nv; ++i) d[i] = infc;
d[src] = 0; pv[src] = src; vis[src] = 1;
for(f = 0, r = 1, que[0] = src; r != f; )
{
i = que[f++]; vis[i] = 0;
if(V == f) f = 0;
for(k = head[i]; k != -1; k = nxt[k])
if(cap[k] && dis[k]+d[i] < d[pnt[k]])
{
d[pnt[k]] = dis[k] + d[i];
if(0 == vis[pnt[k]])
{
vis[pnt[k]] = 1;
que[r++] = pnt[k];
if(V == r) r = 0;
}
pv[pnt[k]] = i; pe[pnt[k]] = k;
}
}
if(-1 == pv[sink]) break;
for(k = sink, mxf = inff; k != src; k = pv[k])
if(cap[pe[k]] < mxf) mxf = cap[pe[k]];
flow += mxf; cost += d[sink] * mxf;
for(k = sink; k != src; k = pv[k])
{
cap[pe[k]] -= mxf; cap[pe[k]^1] += mxf;
}
}
return cost;
}
void init(int v)
{
nv = v; ne = 0;
memset(head, -1, 4 * v);
}
} nw;
struct Lich
{
double x, y, r;
int t;
void input()
{
scanf("%lf %lf %lf %d", &x, &y, &r, &t);
}
} lich[maxn];
struct Wisp
{
double x, y;
void input()
{
scanf("%lf %lf", &x, &y);
}
} wisp[maxn];
struct Tree
{
double x, y, r;
void input()
{
scanf("%lf %lf %lf", &x, &y, &r);
}
} tree[maxn];
int T, N, M, K;
int ecnt[maxn];
double Dot(double dx1, double dy1, double dx2, double dy2)
{
return dx1 * dx2 + dy1 * dy2;
}
double Dis(double x0, double y0, double x1, double y1, double x2, double y2)
{
double a, b, c;
if (fabs(x1 - x2) > fabs(y1 - y2))
{
b = 1.0;
a = b * (y2 - y1) / (x1 - x2);
c = -(a * x1 + b * y1);
}
else
{
a = 1.0;
b = a * (x2 - x1) / (y1 - y2);
c = -(a * x1 + b * y1);
}
return fabs(a * x0 + b * y0 + c) / sqrt(a * a + b * b);
}
bool NoCross(int a, int b)
{
int i;
for (i = 0; i < K; i++)
{
if (Dot(tree[i].x - lich[a].x, tree[i].y - lich[a].y, wisp[b].x - lich[a].x, wisp[b].y - lich[a].y) > 0.0 &&
Dot(tree[i].x - wisp[b].x, tree[i].y - wisp[b].y, lich[a].x - wisp[b].x, lich[a].y - wisp[b].y) > 0.0 &&
Dis(tree[i].x, tree[i].y, lich[a].x, lich[a].y, wisp[b].x, wisp[b].y) < tree[i].r + eps)
return false;
}
return true;
}
bool InRound(int i, int j)
{
double dx = lich[i].x - wisp[j].x;
double dy = lich[i].y - wisp[j].y;
return sqrt(dx * dx + dy * dy) < lich[i].r + eps;
}
void BuildGraph()
{
int i, j;
for (i = 0; i < N; i++)
{
ecnt[i] = 0;
for (j = 0; j < M; j++)
{
if (InRound(i, j) && NoCross(i, j))
{
ecnt[i]++;
nw.addedge(i, N + j, 1, 0);
}
}
}
for (i = 0; i < N; i++)
{
for (j = 0; j < ecnt[i]; j++)
nw.addedge(N + M, i, 1, lich[i].t * j);
}
for (i = 0; i < M; i++)
nw.addedge(N + i, N + M + 1, 1, 0);
}
void Solve()
{
nw.mincost(N + M, N + M + 1);
if (nw.flow != M)
{
printf("-1\n");
return;
}
int ans = 0;
for (int p = nw.head[N+M]; p != -1; p = nw.nxt[p])
{
if (nw.cap[p] == 0 && nw.dis[p] > ans)
ans = nw.dis[p];
}
printf("%d\n", ans);
}
int main()
{
int i;
for (scanf("%d", &T); T; T--)
{
scanf("%d %d %d", &N, &M, &K);
for (i = 0; i < N; i++)
lich[i].input();
for (i = 0; i < M; i++)
wisp[i].input();
for (i = 0; i < K; i++)
tree[i].input();
nw.init(N + M + 2);
BuildGraph();
Solve();
}
return 0;
}