[BZOJ5037] [Jsoi2014]电信网络

题目描述

Description

JYY创建的电信公司,垄断着整个JSOI王国的电信网络。JYY在JSOI王国里建造了很多的通信基站。目前所有的基站
都是使用2G网络系统的。而现在3G时代已经到来了,JYY在思考,要不要把一些基站升级成3G网络的呢?JSOI王国
可以被看作为一个无穷大的二维平面,JYY一共建造了N个通信基站,第i个基站的坐标是(Xi,Yi)。每个基站有一个
通信范围Ri。第i号基站会向所有到其距离不超过Ri的基站发送信息。每个基站升级到3G网络都会有一个收益Si,
这个收益可能是正数(比如基站附近有个大城市,用户很多,赚的流量费也就很多了),也可能是负数(比如基站
周围市场不佳,收益不能填补升级基站本身的投资)。此外,由于原有的使用2G网络系统的基站无法解析从升级成
3G网络系统的基站所发来的信息(但是升级之后的基站是可以解析未升级基站发来的信息的),所以,JYY必须使
得,在升级工作全部完成之后,所有使用3G网络的基站,其通信范围内的基站,也都是使用3G网络的。由于基站数
量很多,你可以帮助JYY计算一下,他通过升级基站,最多能获得的收益是多少吗?

Input

第一行一个整数N;
接下来N行,每行4个整数,Xi,Yi,Ri,Si,表示处在(Xi,Yi)的基站的通信
范围是Ri,升级可以获得的收益是Si。
数据满足任意两个基站的坐标不同。
1≤N≤500,1≤Ri≤20000,|Xi|,|Yi|,|Si|≤10^4。

Output

输出一行一个整数,表示可以获得的最大收益。

Sample Input

5
0 1 7 10
0 -1 7 10
5 0 1 -15
10 0 6 10
15 1 2 -20

Sample Output

5

题目分析

骚年 看到收益可以是正数 也可以是负数 并且有依赖关系 你是否想到最大权闭合子图了呢

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,ans;
int tot=1;
int head[510],to[500000],net[500000],val[500000];
void add(int x,int y,int c)
{
    net[++tot]=head[x],head[x]=tot,to[tot]=y,val[tot]=c;
    net[++tot]=head[y],head[y]=tot,to[tot]=x,val[tot]=0;
}
int S,T;
int dis[510];
int bfs()
{
    queue<int>q;
    memset(dis,0,sizeof dis);
    q.push(S),dis[S]=1;
    while(q.size())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=net[i])
            if(val[i]&&!dis[to[i]])
            {
                dis[to[i]]=dis[x]+1,q.push(to[i]);
                if(to[i]==T) return 1;
            }
    }
    return 0;
}
int dinic(int x,int flow)
{
    int tmp,temp=flow;
    if(x==T) return flow;
    for(int i=head[x];i;i=net[i])
        if(val[i]&&dis[to[i]]==dis[x]+1)
        {
            tmp=dinic(to[i],min(temp,val[i]));
            temp-=tmp,val[i]-=tmp,val[i^1]+=tmp;
            if(!val[i]) dis[to[i]]=0;
            if(!temp) break;
        }
    return flow-temp;
}
int x[510],y[510],s[510],r[510];
int check(int i,int j)
{
    return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])<=r[i]*r[i];
}
int main()
{
    scanf("%d",&n);
    S=0,T=n+1;
    for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&x[i],&y[i],&r[i],&s[i]);
    for(int i=1;i<=n;i++)
    {
        if(s[i]>=0) add(S,i,s[i]),ans+=s[i];
        else add(i,T,-s[i]);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j&&check(i,j))
                add(i,j,1<<30);
    while(bfs()) ans-=dinic(S,1<<30);
    printf("%d",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注