首页 > 代码库 > bzoj 1497 最大获利 - 最小割
bzoj 1497 最大获利 - 最小割
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
Input
输入文件中第一行有两个正整数N和M 。第二行中有N个整数描述每一个通讯中转站的建立成本,依次为P1, P2, …, PN 。以下M行,第(i + 2)行的三个数Ai, Bi和Ci描述第i个用户群的信息。所有变量的含义可以参见题目描述。
Output
你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。
Sample Input
5 51 2 3 4 51 2 32 3 41 3 31 4 24 5 3
Sample Output
4
Hint
【样例说明】选择建立1、2、3号中转站,则需要投入成本6,获利为10,因此得到最大收益4。【评分方法】本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满分,否则不得分。【数据规模和约定】 80%的数据中:N≤200,M≤1 000。 100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。
当要从一个用户获得收益那么就得选择相应的中转站,很像最大权闭合图,于是思考按照它的方法来建图。
用户代表的点和源点连边,容量为对应的收益,中转站代表的点和汇点连边,容量为对应的成本。用户i需要哪两个中转站,点i就向这个中转站连边,容量为无限大。
稍微解释一下这个网络。考虑用户和源点之间的边。当它被割掉了,说明满足这个用户可能收益和成本(只是对于这个用户来说)相等,或者从他这儿得到收益结果会是亏本。如果它没有被割掉,容量和流量的差就是从它这儿得到的收益。
所以最终的答案是收益的总和 - 最小割容量 = 收益的总和 - 最大流流量
Code
1 /** 2 * bzoj 3 * Problem#1497 4 * Accepted 5 * Time:746ms 6 * Memory:14412k 7 */ 8 #include <iostream> 9 #include <cstdio> 10 #include <ctime> 11 #include <cctype> 12 #include <cstring> 13 #include <cstdlib> 14 #include <fstream> 15 #include <sstream> 16 #include <algorithm> 17 #include <map> 18 #include <set> 19 #include <stack> 20 #include <queue> 21 #include <vector> 22 #include <stack> 23 using namespace std; 24 typedef bool boolean; 25 #define inf 0xfffffff 26 #define smin(a, b) a = min(a, b) 27 #define smax(a, b) a = max(a, b) 28 #define max3(a, b, c) max(a, max(b, c)) 29 #define min3(a, b, c) min(a, min(b, c)) 30 template<typename T> 31 inline boolean readInteger(T& u){ 32 char x; 33 int aFlag = 1; 34 while(!isdigit((x = getchar())) && x != ‘-‘ && x != -1); 35 if(x == -1) { 36 ungetc(x, stdin); 37 return false; 38 } 39 if(x == ‘-‘){ 40 x = getchar(); 41 aFlag = -1; 42 } 43 for(u = x - ‘0‘; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - ‘0‘); 44 ungetc(x, stdin); 45 u *= aFlag; 46 return true; 47 } 48 49 template<typename T>class Matrix{ 50 public: 51 T *p; 52 int lines; 53 int rows; 54 Matrix():p(NULL){ } 55 Matrix(int rows, int lines):lines(lines), rows(rows){ 56 p = new T[(lines * rows)]; 57 } 58 T* operator [](int pos){ 59 return (p + pos * lines); 60 } 61 }; 62 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) 63 64 typedef class Edge { 65 public: 66 int end; 67 int next; 68 int flow; 69 int cap; 70 Edge(int end = 0, int next = -1, int flow = 0, int cap = 0):end(end), next(next), flow(flow), cap(cap) { } 71 }Edge; 72 73 typedef class MapManager { 74 public: 75 int ce; 76 vector<Edge> edge; 77 int* h; 78 79 MapManager():ce(0), h(NULL) { } 80 MapManager(int nodes):ce(0) { 81 h = new int[(const int)(nodes + 1)]; 82 memset(h, -1, sizeof(int) * (nodes + 1)); 83 } 84 85 inline void addEdge(int from, int end, int flow, int cap) { 86 edge.push_back(Edge(end, h[from], flow, cap)); 87 h[from] = ce++; 88 } 89 90 inline void addDoubleEdge(int from, int end, int cap) { 91 if(cap == 0) return; 92 addEdge(from, end, 0, cap); 93 addEdge(end, from, cap, cap); 94 } 95 96 Edge& operator [] (int pos) { 97 return edge[pos]; 98 } 99 }MapManager;100 #define m_begin(g, i) (g).h[(i)]101 #define m_endpos -1102 103 typedef class Point {104 public:105 int x;106 int y;107 Point(int x = 0, int y = 0):x(x), y(y) { }108 }Point;109 110 int n, m;111 int* p;112 int *a, *b, *c;113 MapManager g;114 115 int s, t;116 117 inline void init() {118 readInteger(n);119 readInteger(m);120 p = new int[(const int)(n + 1)];121 a = new int[(const int)(m + 1)];122 b = new int[(const int)(m + 1)];123 c = new int[(const int)(m + 1)];124 for(int i = 1; i <= n; i++)125 readInteger(p[i]);126 for(int i = 1; i <= m; i++) {127 readInteger(a[i]);128 readInteger(b[i]);129 readInteger(c[i]);130 }131 }132 133 int sum = 0;134 inline void init_map() {135 s = 0, t = n + m + 1;136 g = MapManager(t);137 for(int i = 1; i <= m; i++) {138 g.addDoubleEdge(s, i, c[i]);139 g.addDoubleEdge(i, a[i] + m, inf);140 g.addDoubleEdge(i, b[i] + m, inf);141 sum += c[i];142 }143 for(int i = 1; i <= n; i++)144 g.addDoubleEdge(i + m, t, p[i]);145 }146 147 int* dis;148 boolean* vis;149 queue<int> que;150 inline boolean bfs() {151 memset(vis, false, sizeof(boolean) * (t + 3));152 que.push(s);153 vis[s] = true;154 dis[s] = 0;155 while(!que.empty()) {156 int e = que.front();157 que.pop();158 for(int i = m_begin(g, e); i != m_endpos; i = g[i].next) {159 if(g[i].cap == g[i].flow) continue;160 int eu = g[i].end;161 if(vis[eu]) continue;162 vis[eu] = true;163 dis[eu] = dis[e] + 1;164 que.push(eu);165 }166 }167 return vis[t];168 }169 170 int *cur;171 inline int blockedflow(int node, int minf) {172 if((node == t) || (minf == 0)) return minf;173 int f, flow = 0;174 for(int& i = cur[node]; i != m_endpos; i = g[i].next) {175 int& eu = g[i].end;176 if(dis[eu] == dis[node] + 1 && g[i].flow < g[i].cap && (f = blockedflow(eu, min(minf, g[i].cap - g[i].flow))) > 0) {177 minf -= f;178 flow += f;179 g[i].flow += f;180 g[i ^ 1].flow -= f;181 if(minf == 0) return flow;182 }183 }184 return flow;185 }186 187 inline void init_dinic() {188 vis = new boolean[(const int)(t + 3)];189 dis = new int[(const int)(t + 3)];190 cur = new int[(const int)(t + 3)];191 }192 193 inline int dinic() {194 int maxflow = 0;195 while(bfs()) {196 for(int i = 0; i <= t; i++)197 cur[i] = m_begin(g, i);198 maxflow += blockedflow(s, inf);199 }200 return maxflow;201 }202 203 inline void solve() {204 printf("%d\n", sum - dinic());205 }206 207 int main() {208 init();209 init_map();210 init_dinic();211 solve();212 return 0;213 }
bzoj 1497 最大获利 - 最小割