题解:P14122 [SCCPC 2021] Direction Setting
一个简简单单的费用流。
纪念自己切的第不知道多少道蓝题。
题解
这道题目应该很好想吧,我一开始还乱搞导致白白浪费了很多小时。
不难发现,结果要我们统计的是节点的度数,与那个节点指向它没有关系,所以对问题进行转化,即对点
边点向点
现在只剩一个问题了,度数减去限制
代码
真的很好写。
#include <bits/stdc++.h>
#define ll long long
#define pub push_back
using namespace std;
const int N = 905, inf = 1e9;
int T, n, m, cur[N], dis[N], s, t, ans2, jl[305];
bool vis[N];
struct Node{int to, w, c, fx;};
vector <Node> ed[N];
void add(int u, int v, int w, int c){
int tmp = ed[v].size(), tmp2 = ed[u].size();
ed[u].pub({v, w, c, tmp}), ed[v].pub({u, 0, -c, tmp2});
}
queue <int> q;
bool spfa(){
for(int i = 1;i <= t;i++) dis[i] = inf;
dis[s] = 0, q.push(s), vis[s] = 1;
while(!q.empty()){
int tmp = q.front();
q.pop(), vis[tmp] = 0;
for(auto bl : ed[tmp]){
int i = bl.to, bw = bl.w, fy = bl.c;
if(bw && dis[tmp] + fy < dis[i]){
dis[i] = dis[tmp] + fy;
if(!vis[i]) q.push(i), vis[i] = 1;
}
}
}
return dis[t] != inf;
}
int dfs(int x, int dl){
if(x == t || !dl) return dl;
int sum = 0, js = 0;
vis[x] = 1;
for(auto &bl : ed[x]){
if(++js < cur[x]) continue;
cur[x] = js;
int i = bl.to, bw = bl.w, fy = bl.c;
if(bw && dis[i] == dis[x] + fy && !vis[i]){
int hl = dfs(i, min(dl, bw));
bl.w -= hl, ed[i][bl.fx].w += hl;
sum += hl, dl -= hl, ans2 += hl * fy;
if(dl == 0) break;
}
}
if(sum == 0) dis[x] = inf;
vis[x] = 0;
return sum;
}
void qzdl(){
int tmp;
while(spfa()){
memset(cur, 0, sizeof cur);
dfs(s, inf);
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> T;
while(T--){
cin >> n >> m, s = n + m + 1, t = n + m + 2;
for(int i = 1;i <= n;i++){
int x;
cin >> x, add(i + m, t, x, 0);
add(i + m, t, inf, 1);
}
for(int i = 1;i <= m;i++){
int u, v;
cin >> u >> v, jl[i] = v;
add(s, i, 1, 0), add(i, u + m, 1, 0);
if(u != v) add(i, v + m, 1, 0);
}
ans2 = 0, qzdl(), cout << ans2 << "\n";
for(int i = 1;i <= m;i++)
for(auto bl : ed[i]){
int j = bl.to, bw = bl.w;
if(j > m && j <= m + n && bw == 0){
if(j - m == jl[i]) cout << "0";
else cout << "1";
break;
}
}
cout << "\n";
for(int i = 1;i <= t;i++) ed[i].clear();
}
return 0;
}