题面
题解
选某个点就必须选其他的点
最大权闭合子图
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int N = 505;
const int INF = 0x3f3f3f3f;
using namespace std;
int n, x[N], y[N], r[N], S, T, cnt = 1, head[N], d[N], cur[N], sum;
struct edge { int to, nxt, flow; } e[N * N * 4];
queue<int> q;
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
int mabs(int x) { return x > 0 ? x : -x; }
inline void adde(int u, int v, int w)
{
e[++cnt] = (edge) { v, head[u], w }, head[u] = cnt;
e[++cnt] = (edge) { u, head[v], 0 }, head[v] = cnt;
}
bool check(int i, int j) { return mabs(x[i] - x[j]) * mabs(x[i] - x[j]) + mabs(y[i] - y[j]) * mabs(y[i] - y[j]) <= r[i] * r[i]; }
bool bfs()
{
memset(d, 0, sizeof(d)), d[S] = 1, q.push(S);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int v, i = head[u]; i; i = e[i].nxt)
{
v = e[i].to;
if(!d[v] && e[i].flow > 0)
d[v] = d[u] + 1, q.push(v);
}
}
return d[T];
}
int dfs(int u, int a)
{
if(u == T || !a) return a;
int f = 0;
for(int v, &i = cur[u]; i; i = e[i].nxt)
{
v = e[i].to;
if(e[i].flow > 0 && d[v] == d[u] + 1)
{
int tmp = dfs(v, min(a, e[i].flow));
f += tmp, a -= tmp, e[i].flow -= tmp, e[i ^ 1].flow += tmp;
}
if(!a) break;
}
if(a) d[u] = 0;
return f;
}
int dinic()
{
int flow = 0;
while(bfs())
memcpy(cur, head, sizeof(cur)), flow += dfs(S, INF);
return flow;
}
int main()
{
n = read <int> (), S = n + 1, T = S + 1;
for(int k, i = 1; i <= n; i++)
{
x[i] = read <int> (), y[i] = read <int> (), r[i] = read <int> ();
k = read <int> ();
if(k > 0) sum += k, adde(S, i, k);
else adde(i, T, -k);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i != j && check(i, j)) adde(i, j, INF);
printf("%d\n", sum - dinic());
return 0;
}