[题解] [JSOI2014] 电信网络

让人想犯罪 __ 提交于 2020-02-11 22:02:22

题面

题解

选某个点就必须选其他的点

最大权闭合子图

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; 
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!