Loading

洛谷-P4014 分配问题

分配问题

二分图 + 费用流

建图:

  1. 源点与人相连,容量为 \(1\),费用为 \(0\)

  2. 汇点与工作相连,容量为 \(1\), 费用为 \(0\)

  3. 人与工作一一相连,容量为 \(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;
}
posted @ 2022-06-22 22:34  dgsvygd  阅读(34)  评论(0编辑  收藏  举报