(1)题目大意
给你一个无向图,你需要修改成有向图,问你修改完之后每一个点入度-a[i]的和的最小是多少。
(2)解题思路
对于每一条边,我们给他抽象成一个点,这个题就转变为了最小费用最大流模型,考虑建边。
对于第i条边L,R,首先有一条从源点到i容量为1,费用为0的管道
对于L,有一条从i到m+L容量为1,费用为0的管道
对于R,有一条从i到m+R容量为1,费用为0的管道
对于每一个点,我们都有从当前点向汇点的容量为a[i],费用为0的管道
对于每一个点,我们都有从当前点向汇点的容量为INF,费用为1的管道
然后跑一个EK算一下最小费用流即可。
(3)代码实现
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 3210;
int he[N],w[N],id[N],pre[N],dis[N],mf[N],vis[N],idx;
struct Edge {
int nt,to;
int rl,fw;
}E[N];
int S,T,maxf,minv;
int n,m;
const int inf = 0x3f3f3f3f;
void add(int a,int b,int rl,int fw)
{
E[idx] = {he[a],b,rl,fw};
he[a] = idx ++;
E[idx] = {he[b],a,0,-fw};
he[b] = idx ++;
}
bool spfa()
{
rep(i,0,T) {
vis[i] = mf[i] = 0;
dis[i] = inf;
}
dis[S] = 0,mf[S] = inf;
queue <int> q;
q.push(S);
while(sz(q)) {
int v = q.front();
q.pop();
vis[v] = false;
for(int i = he[v];~i;i = E[i].nt) {
int j = E[i].to,W = E[i].fw,rl = E[i].rl;
if(dis[j] > dis[v] + W && rl) {
dis[j] = dis[v] + W;
mf[j] = min(mf[v],rl);
pre[j] = i;
if(!vis[j]) {
vis[j] = true;
q.push(j);
}
}
}
}
return mf[T] > 0;
}
void EK()
{
while(spfa()) {
for(int V = T;V != S;) {
int i = pre[V];
E[i].rl -= mf[T];
E[i ^ 1].rl += mf[T];
V = E[i ^ 1].to;
}
maxf += mf[T];
minv += dis[T] * mf[T];
}
}
void solve()
{
cin >> n >> m;
memset(he,-1,sizeof(he));
rep(i,1,n) cin >> w[i];
maxf = 0,minv = 0;
//把边抽象成点
idx = 0,S = 0,T = n + m + 1;
int L,R;
rep(i,1,m) {
add(S,i,1,0);
id[i] = idx;
cin >> L >> R;
add(i,m + L,1,0);
add(i,m + R,1,0);
}
rep(i,1,n) {
add(i + m,T,w[i],0);
add(i + m,T,inf,1);
}
EK();
cout << minv << '\n';
rep(i,1,m) {
int k = id[i];
if(E[k].rl == 0) cout << 1;
else cout << 0;
}
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
cin >> T;
while(T --) solve();
return 0;
}