Step1 Problem:
给你 n 个点,m 条流量下界是 low ,上界是 up 的单向边。问你能否满足每时每刻每条边的流量都在 [low, up] 范围内,如果不满足输出 NO, 满足输出 YES 同时输出每条边的流量。
Step2 Ideas:
上下界网络流和平常的网络流不同在于多出了两个点:超级源点 S, 超级汇点 T.
超级源点 S:每条边下界流量都由 S 流出,这样原图就可以变成没有下界的容量为 up-low 的图了。
超级汇点 T:T 是用来判断 流入每个点的流量 是否够 它流出的下界。
知道 S, T 的作用后:
例如:一条边 u -> v,下界 low, 上界 up.
那么 S -> v 流入 low,u -> T 流入 low,u-> v 流入 up-low. (这样就没有下界了)
S -> v 流入 low:S 充当了 u 流向 v 的下界
u -> T 流入 low:如果 u 有流量 low 流入 T,代表有流量 low 可以到达 u,那么 u->v 的下界流量肯定能满足
u-> v 流入 up-low:S 充当了 u 流向 v 的下界,所以我的上下界都得减少 low.
对于新图跑 S 到 T 的最大流,如果 T 收到流量是满流的 或者 S 发出去的流量是满流的,就代表所有下界流量都能满足。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 50000;
const int N = 500;
struct node
{
int to, cap, next;
}Map[M];
int head[N], cnt;
int lsum[N], bl[N*N];
int vis[N], cur[N];
int ans[N*N];
bool bfs(int s, int e)
{
memset(vis, -1, sizeof(vis));
queue<int> q;
q.push(s);
vis[s] = 0;
while(!q.empty())
{
s = q.front(), q.pop();
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, cap = Map[i].cap;
if(cap && vis[to] == -1)
{
vis[to] = vis[s] + 1;
q.push(to);
}
}
}
if(vis[e] == -1) return 0;
else return 1;
}
int dfs(int s, int e, int f)
{
if(s == e) return f;
int ans = 0;
for(int &i = cur[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, &cap = Map[i].cap;
if(vis[to] > vis[s] && cap)
{
int d = dfs(to, e, min(f, cap));
if(d)
{
cap -= d;
Map[i^1].cap += d;
f -= d;
ans += d;
if(!f) break;
}
}
}
if(ans) return ans;
vis[s] = -1;
return 0;
}
int dinic(int s, int e)
{
int ans = 0;
while(bfs(s, e))
{
memcpy(cur, head, sizeof(head));
ans += dfs(s, e, inf);
}
return ans;
}
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
memset(lsum, 0, sizeof(lsum));
memset(bl, 0, sizeof(bl));
}
void add(int u, int v, int cap)
{
Map[cnt] = (node){v, cap, head[u]};
head[u] = cnt++;
Map[cnt] = (node){u, 0, head[v]};
head[v] = cnt++;
}
int main()
{
int T, n, m, u, v, low, up;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d %d", &n, &m);
int S = 0, T = n+1;
for(int i = 1; i <= m; i++)
{
scanf("%d %d %d %d", &u, &v, &low, &up);
add(u, v, up-low);
lsum[v] += low; //流入 v 的下界和
lsum[u] -= low; //流出 u 的下界和
bl[i] = low;
}
int sum = 0;// S 发出去的流量
for(int i = 1; i <= n; i++)
{
if(lsum[i] > 0) {
sum += lsum[i];
add(S, i, lsum[i]);//流入比流出多
}
if(lsum[i] < 0) add(i, T, -lsum[i]);//流出比流入多
}
if(sum != dinic(S, T)) {//如果最大流不等于发出去的流量,则不满足
printf("NO\n");
}
else {
printf("YES\n");
for(int i = 1; i <= m; i++) {//每条边在下界的基础上多流了多少流量
int id = (i-1)*2;
ans[i] = Map[id^1].cap;
}
for(int i = 1; i <= m; i++)
{
printf("%d\n", ans[i]+bl[i]);
}
}
printf("\n");
}
return 0;
}