【bzoj5037】[Jsoi2014]电信网络 最大权闭合图
题目描述
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计算一下,他通过升级基站,最多能获得的收益是多少吗?
输入
第一行一个整数N;
接下来N行,每行4个整数,Xi,Yi,Ri,Si,表示处在(Xi,Yi)的基站的通信范围是Ri,升级可以获得的收益是Si。数据满足任意两个基站的坐标不同。
1≤N≤500,1≤Ri≤20000,|Xi|,|Yi|,|Si|≤10^4。
输出
输出一行一个整数,表示可以获得的最大收益。
样例输入
5
0 1 7 10
0 -1 7 10
5 0 1 -15
10 0 6 10
15 1 2 -20
样例输出
5
题解
最大权闭合图
选xxx就必须选xxx,求最大总收益,显然最大权闭合图问题。
用两点间距离公式求出选某个就必须选哪些,然后建图最小割,没了。。
#include <queue>
#include <cstdio>
#include <cstring>
#define N 510
#define M 1000010
#define inf 1 << 30
using namespace std;
queue<int> q;
int x[N] , y[N] , r[N] , v[N] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
inline void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
memset(dis , 0 , sizeof(dis));
while(!q.empty()) q.pop();
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
int main()
{
int n , i , j , sum = 0;
scanf("%d" , &n) , s = 0 , t = n + 1;
for(i = 1 ; i <= n ; i ++ )
{
scanf("%d%d%d%d" , &x[i] , &y[i] , &r[i] , &v[i]);
if(v[i] > 0) add(s , i , v[i]) , sum += v[i];
else add(i , t , -v[i]);
}
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= n ; j ++ )
if(i != j && (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= r[i] * r[i])
add(i , j , inf);
while(bfs()) sum -= dinic(s , inf);
printf("%d\n" , sum);
return 0;
}
浙公网安备 33010602011771号