思路
最小费用最大流,把每条边看成一个点,和这条边连通的两点连边,流量为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;
}
}