• [BZOJ1497][NOI2006]最大获利


    [BZOJ1497][NOI2006]最大获利

    试题描述

    新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。在前期市场调查和站址勘测之后,公司得到了一共 (N) 个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为 (P_i)(1 le i le N))。另外公司调查得出了所有期望中的用户群,一共 (M) 个。关于第 (i) 个用户群的信息概括为 (A_i), (B_i)(C_i):这些用户会使用中转站 (A_i) 和中转站 (B_i) 进行通讯,公司可以获益
    (C_i)。((1 le i le M, 1 le A_i, B_i le N)) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

    输入

    输入文件中第一行有两个正整数 (N)(M)。第二行中有N个整数描述每一个通讯中转站的建立成本,依次为 (P_1, P_2, …, P_N) 。以下 (M) 行,第 ((i + 2)) 行的三个数 (A_i), (B_i)(C_i) 描述第 (i) 个用户群的信息。所有变量的含义可以参见题目描述。

    输出

    你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。

    输入示例

    5 5
    1 2 3 4 5
    1 2 3
    2 3 4
    1 3 3
    1 4 2
    4 5 3
    

    输出示例

    4
    

    数据规模及约定

    (100 exttt{%}) 的数据中:(N le 5000)(M le 50000)(0 le C_i le 100)(0 le P_i le 100)

    题解

    最小割套路题。先把所有收益都拿到,然后两种可能的花费,要么建立一个中转站,要么抛弃一个客户。所以从源点向中转站连权值为花费的边,两个中转站向一个客户连权值无穷的边,客户向汇点连权值为收益的边。跑最小割。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 55010
    #define maxm 400010
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow;
    	Edge() {}
    	Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
    };
    struct Dinic {
    	int n, m, s, t, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	int vis[maxn], Q[maxn], hd, tl;
    	int cur[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c) {
    		es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		memset(vis, 0, sizeof(vis));
    		hd = tl = 0; Q[++tl] = t;
    		vis[t] = 1;
    		while(hd < tl) {
    			int u = Q[++hd];
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(!vis[e.from] && e.flow) {
    					vis[e.from] = vis[u] + 1;
    					Q[++tl] = e.from;
    				}
    			}
    		}
    		return vis[s] > 0;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return a;
    		int flow = 0, f;
    		for(int& i = cur[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0;
    		while(BFS()) {
    			rep(i, 1, n) cur[i] = head[i];
    			flow += DFS(s, oo);
    		}
    		return flow;
    	}
    } sol;
    
    int CntP;
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++CntP; }
    } node[maxn], per[maxn], S, T;
    
    int main() {
    	int n = read(), m = read();
    	sol.init();
    	rep(i, 1, n) sol.AddEdge(S.p(), node[i].p(), read());
    	int ans = 0;
    	rep(i, 1, m) {
    		int a = read(), b = read(), c = read();
    		sol.AddEdge(node[a].p(), per[i].p(), oo);
    		sol.AddEdge(node[b].p(), per[i].p(), oo);
    		sol.AddEdge(per[i].p(), T.p(), c);
    		ans += c;
    	}
    	sol.setn(CntP);
    	printf("%d
    ", ans - sol.MaxFlow(S.p(), T.p()));
    	
    	return 0;
    }
    

    这题可以讨论一对点属于 (S) 割还是 (T) 割的 (4) 种情况,优化建图。

    对于所有中转站,从源点向他们连权值等于花费的边;对于一个客户在对应两个点之间连权值为 (frac{花费}{2}) 的双向边,从这两个点向汇点连权值为 (frac{花费}{2}) 的边。

  • 相关阅读:
    jQuery 事件注册
    jQuery 获取元素当前位置offset()与position()
    jquery scrollTop()与scrollLeft()
    linux常用命令
    php5.6+apache2.4环境配置
    php 开启socket配置
    Node.js的学习路线
    apache配置rewrite及.htaccess文件(转载)
    php 获取域名等Url
    html5的本地存储
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7900659.html
Copyright © 2020-2023  润新知