BZOJ 1497 [NOI2006]最大获利

BZOJ 1497 [NOI2006]最大获利

从原点向每个中转站建立容量为$p_i$的边,再从中转站向以它作为条件的用户群建立$+\infin$的边,最后从用户群向汇点建立$c_i$的边,医院的权值和 - 最小割就是答案。

为什么这样是对的呢?考虑我们满足一个用户组的需求,无非就是不要这个需求(割掉这个边)或者花代价去割掉它的$A_i,B_i$,这样做它的盈利是$c_i - p_a-p_b$。所以最后求和 c 减去最小割就是答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "queue"
#include "cmath"
#include "vector"
using namespace std;
#define mem(a) memset( a , 0 , sizeof a )
#define MAXN 6006
#define inf 0x3f3f3f3f

typedef long long ll;
class maxFlow {
private:
int add(int u, int v, ll w) {
nxt.push_back(head[u]);
int x = ( head[u] = to.size() );
to.push_back(v);
cap.push_back(w);
return x;
}
public:
std::queue<int> q;
std::vector<int> head, cur, nxt, to, dep;
std::vector<ll> cap;

maxFlow(int _n = 0) { init(_n); }
void init(int _n) {
head.clear();
head.resize(_n + 1, 0);
nxt.resize(2);
to.resize(2);
cap.resize(2);
}
void init() { init(head.size() - 1); }
int Add(int u, int v, ll w) {
// printf("%d %d %d\n",u,v,w);
add(u, v, w);
return add(v, u, 0);
}
void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
bool bfs(int s, int t, int delta) {
dep.clear();
dep.resize(head.size(), -1);
dep[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == -1) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return ~dep[t];
}
ll dfs(int u, ll flow, int t, int delta) {
if (dep[u] == dep[t])
return u == t ? flow : 0;
ll out = 0;
for (int& i = cur[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == dep[u] + 1) {
ll f = dfs(v, std::min(w, flow - out), t, delta);
cap[i] -= f;
cap[i ^ 1] += f;
out += f;
if (out == flow)
return out;
}
}
return out;
}
ll maxflow(int s, int t) {
ll out = 0;
ll maxcap = *max_element(cap.begin(), cap.end());
for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
while (bfs(s, t, delta)) {
cur = head;
out += dfs(s, 0x7fffffffffffffffll, t, delta);
}
}
return out;
}
ll getflow(int x) const { return cap[x << 1 | 1]; }
} F ;
int n , m , s = 60001 , t = 60002;
int p[MAXN];
long long S;
int main() {
cin >> n >> m;
F.init( 60006 );
for( int i = 1 ; i <= n ; ++ i ) scanf("%d",&p[i]) , F.Add( s , i , p[i] );
for( int i = 1,a,b,c ; i <= m ; ++ i ) {
scanf("%d%d%d",&a,&b,&c);
F.Add( i + n , t , c ) , F.Add( a , i + n , inf ) , F.Add( b , i + n , inf );
S += c;
}
cout << S - F.maxflow( s , t ) << endl;
}
文章作者: yijan
文章链接: https://yijan.co/old38/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog