【2021四川省赛】F-Direction Setting (费用流)

思路

最小费用最大流,把每条边看成一个点,和这条边连通的两点连边,流量为1,费用为0。
超级起点和每条边都建一条边,同样流量为1,费用为0。
每个点和超级汇点建两条边,一条流量为a[i],单位费用为0,一条流量为INF,单位费用为1,跑一遍最小费用。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <list>
#include <map>
#include <iostream>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define LL long long
#define inf 0x3f3f3f3f
//#define INF 0x3f3f3f3f3f3f
#define PI acos(-1.0)
#define F first
#define S second
#define endl '\n'
#define lson rt << 1
#define rson rt << 1 | 1
#define lowbit(x) (x & (-x))
#define f(x, y, z) for (int x = (y), __ = (z); x < __; ++x)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _per(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
const int maxn = 3e3 + 7;
const int maxm = 1e9 + 1;
const LL mod = 1e9 + 7;
int n, m;
int a[maxn], b[maxn];
namespace MCMF
{
    const int MAXN = 1e3 + 7, MAXM = 3e3 + 7;
    int head[MAXN], cnt = 1;
    struct Edge
    {
        int to, w, c, next;
    } edges[MAXM * 2];
    inline void add(int from, int to, int w, int c)
    {
        edges[++cnt] = {to, w, c, head[from]};
        head[from] = cnt;
    }
    inline void addEdge(int from, int to, int w, int c)
    {
        add(from, to, w, c);
        add(to, from, 0, -c);
    }
    int s, t, dis[MAXN], cur[MAXN];
    bool inq[MAXN], vis[MAXN];
    queue<int> Q;
    bool SPFA()
    {
        while (!Q.empty())
            Q.pop();
        copy(head, head + MAXN, cur);
        fill(dis, dis + MAXN, inf);
        dis[s] = 0;
        Q.push(s);
        while (!Q.empty())
        {
            int p = Q.front();
            Q.pop();
            inq[p] = 0;
            for (int e = head[p]; e != 0; e = edges[e].next)
            {
                int to = edges[e].to, vol = edges[e].w;
                if (vol > 0 && dis[to] > dis[p] + edges[e].c)
                {
                    dis[to] = dis[p] + edges[e].c;
                    if (!inq[to])
                    {
                        Q.push(to);
                        inq[to] = 1;
                    }
                }
            }
        }
        return dis[t] != inf;
    }
    int dfs(int p = s, int flow = inf)
    {
        if (p == t)
            return flow;
        vis[p] = 1;
        int rmn = flow;
        for (int eg = cur[p]; eg && rmn; eg = edges[eg].next)
        {
            cur[p] = eg;
            int to = edges[eg].to, vol = edges[eg].w;
            if (vol > 0 && !vis[to] && dis[to] == dis[p] + edges[eg].c)
            {
                int c = dfs(to, min(vol, rmn));
                rmn -= c;
                edges[eg].w -= c;
                edges[eg ^ 1].w += c;
            }
        }
        vis[p] = 0;
        return flow - rmn;
    }
    int maxflow, mincost;
    inline void init()
    {
        cnt = 1;
        memset(head, 0, sizeof(head));
        maxflow = mincost = 0;
    }
    inline void run(int s, int t)
    {
        MCMF::s = s, MCMF::t = t;
        while (SPFA())
        {
            int flow = dfs();
            maxflow += flow;
            mincost += dis[t] * flow;
        }
    }
}
using namespace MCMF;
int main()
{

    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        init();
        _rep(i, 1, n) cin >> a[i];
        int u, v;
        _rep(i, 1, m)
        {
            cin >> u >> v;
            b[i] = v;
            addEdge(n + m + 1, n + i, 1, 0);
            addEdge(n + i, u, 1, 0);
            addEdge(n + i, v, 1, 0);
        }
        _rep(i, 1, n)
        {
            addEdge(i, n + m + 2, a[i], 0);
            addEdge(i, n + m + 2, inf, 1);
        }
        run(n + m + 1, n + m + 2);
        cout << mincost << endl;
        _rep(i, n + 1, n + m)
        {
            for (int j = head[i]; j; j = edges[j].next)
            {
                int v = edges[j].to;
                if (edges[j].w)
                    continue;
                if (v == b[i - n])
                    cout
                        << 0;
                else
                    cout << 1;
                break;
            }
        }
        cout << endl;
    }
}
上一篇:poj 3083(不是特别难,但是很麻烦)


下一篇:LeetCode-6- Z 字形变换