【2021四川省賽】F-Direction Setting (費用流)
阿新 • • 發佈:2021-07-28
思路
最小費用最大流,把每條邊看成一個點,和這條邊連通的兩點連邊,流量為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; } }