洛谷-P4014 分配问题
分配问题
二分图 + 费用流
建图:
-
源点与人相连,容量为 \(1\),费用为 \(0\)
-
汇点与工作相连,容量为 \(1\), 费用为 \(0\)
-
人与工作一一相连,容量为 \(1\),费用为对应的效率
最小费用最大流模板
最大费用最大流的时候,只需要把费用更改为负数即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e3 + 10;
const int maxm = 1e5 + 10;
const int inf = 1e9 + 10;
int s = 0, t = 0, tp = 1, n = 0, cur[maxn], head[maxn], vis[maxn];
int val[maxm], nex[maxm], to[maxm], cost[maxm], dis[maxn];
int last = 0;
void add(int u, int v, int w, int f)
{
tp++;
cost[tp] = f;
nex[tp] = head[u];
head[u] = tp;
to[tp] = v;
val[tp] = w;
}
bool spfa()
{
queue<int>q;
q.push(s);
for(int i=0; i<=n; i++) cur[i] = head[i];
for(int i=0; i<=n; i++) dis[i] = inf;
dis[s] = 0;
while(q.size())
{
int now = q.front();
q.pop();
vis[now] = 0;
for(int i=head[now]; i; i=nex[i])
{
int u = to[i];
if(val[i] <= 0 || dis[now] + cost[i] >= dis[u]) continue;
dis[u] = dis[now] + cost[i];
if(vis[u] == 0 && u != t)
{
vis[u] = 1;
q.push(u);
}
}
}
return dis[t] != inf;
}
int dfs(int now, int flow)
{
if(now == t) return flow;
int ans = 0;
vis[now] = 1;
for(int i=cur[now]; i && ans < flow; i=nex[i])
{
int u = to[i];
cur[now] = i;
if(val[i] <= 0 || vis[u] == 1 || dis[u] != dis[now] + cost[i]) continue;
int x = dfs(u, min(val[i], flow - ans));
val[i] -= x;
val[i ^ 1] += x;
ans += x;
last += x * cost[i];
}
vis[now] = 0;
return ans;
}
int dinic()
{
last = 0;
int ans = 0;
while(spfa())
ans += dfs(s, inf);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
s = (n << 1) + 1;
t = s + 1;
for(int i=1; i<=n; i++)
{
add(s, i, 1, 0);
add(i, s, 0, 0);
add(i + n, t, 1, 0);
add(t, i + n, 0, 0);
for(int j=1; j<=n; j++)
{
int x;
cin >> x;
add(i, j + n, 1, x);
add(j + n, i, 0, -x);
}
}
n = 2 * n + 2;
dinic();
cout << last << endl;
for(int i=1; i<=n; i++)
{
for(int j=head[i]; j; j=nex[j])
{
cost[j] = -cost[j];
val[j] = (j & 1) ^ 1;
}
}
dinic();
cout << -last << endl;
return 0;
}