1. 程式人生 > >bzoj 1497 最大獲利 - 最小割

bzoj 1497 最大獲利 - 最小割

col stdin getchar() 關於 tro 一行 strong 我們 之間

新的技術正沖擊著手機通訊市場,對於各大運營商來說,這既是機遇,更是挑戰。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 5
1 2 3 4 5
1 2 3
2 3 4
1 3 3
1 4 2
4 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 -1 102 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 最大獲利 - 最小割