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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
struct MinCostMaxFlow {
struct Edge {
int to;
int rev;
int cap;
long long cost;
};
int nodeCount;
vector<vector<Edge>> graph;
MinCostMaxFlow(int n) : nodeCount(n), graph(n) {}
void addEdge(int from, int to, int capacity, long long cost) {
Edge forward{to, (int)graph[to].size(), capacity, cost};
Edge backward{from, (int)graph[from].size(), 0, -cost};
graph[from].push_back(forward);
graph[to].push_back(backward);
}
pair<long long, long long> minCostMaxFlow(int source, int sink) {
const long long INF = numeric_limits<long long>::max() / 4;
long long totalFlow = 0;
long long totalCost = 0;
vector<long long> potential(nodeCount, 0), distance(nodeCount);
vector<int> parentNode(nodeCount), parentEdgeIndex(nodeCount);
while (true) {
fill(distance.begin(), distance.end(), INF);
distance[source] = 0;
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;
pq.push({0, source});
while (!pq.empty()) {
auto [distU, u] = pq.top();
pq.pop();
if (distU != distance[u]) continue;
for (int i = 0; i < (int)graph[u].size(); ++i) {
const Edge &e = graph[u][i];
if (e.cap <= 0) continue;
long long newDist = distU + e.cost + potential[u] - potential[e.to];
if (newDist < distance[e.to]) {
distance[e.to] = newDist;
parentNode[e.to] = u;
parentEdgeIndex[e.to] = i;
pq.push({newDist, e.to});
}
}
}
if (distance[sink] == INF) break;
for (int v = 0; v < nodeCount; ++v) {
if (distance[v] < INF) potential[v] += distance[v];
}
int addFlow = INT_MAX;
for (int v = sink; v != source; v = parentNode[v]) {
const Edge &e = graph[parentNode[v]][parentEdgeIndex[v]];
addFlow = min(addFlow, e.cap);
}
for (int v = sink; v != source; v = parentNode[v]) {
Edge &e = graph[parentNode[v]][parentEdgeIndex[v]];
Edge &rev = graph[v][e.rev];
e.cap -= addFlow;
rev.cap += addFlow;
totalCost += (long long)addFlow * e.cost;
}
totalFlow += addFlow;
}
return {totalFlow, totalCost};
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int numPeople, numShops;
if (!(cin >> numPeople >> numShops)) return 0;
vector<int> demand(numPeople);
for (int i = 0; i < numPeople; ++i) cin >> demand[i];
vector<int> supply(numShops);
for (int i = 0; i < numShops; ++i) cin >> supply[i];
vector<vector<int>> cost(numShops, vector<int>(numPeople));
for (int i = 0; i < numShops; ++i) {
for (int j = 0; j < numPeople; ++j) {
cin >> cost[i][j];
}
}
int source = 0;
int shopStart = 1;
int personStart = shopStart + numShops;
int sink = personStart + numPeople;
int totalNodes = sink + 1;
MinCostMaxFlow mcmf(totalNodes);
for (int i = 0; i < numShops; ++i) {
mcmf.addEdge(source, shopStart + i, supply[i], 0);
}
for (int j = 0; j < numPeople; ++j) {
mcmf.addEdge(personStart + j, sink, demand[j], 0);
}
for (int i = 0; i < numShops; ++i) {
for (int j = 0; j < numPeople; ++j) {
int cap = min(supply[i], demand[j]);
mcmf.addEdge(shopStart + i, personStart + j, cap, cost[i][j]);
}
}
auto [flow, minCost] = mcmf.minCostMaxFlow(source, sink);
cout << minCost << '\n';
return 0;
}
|