• 【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
    " , sum);
    	return 0;
    }
    

     

  • 相关阅读:
    【原创】Javascript-获取URL请求参数
    【原创】Javascript-显示系统时间
    【转载】ASP.NET 生成验证码
    【转载】Word2010编号列表&多级列表
    VirtualBox命令更改虚拟硬盘空间
    查看应用程序或服务端口号
    【原创】设置EXCEL2010打开多个独立窗口
    【原创】Word2010 清除样式
    【原创】打开Excel时提示"您尝试打开的文件**.xls的格式与文件扩展名指定的格式不一致"
    【转载】SQL Server XML Path
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7491411.html
Copyright © 2020-2023  润新知