给n个点和m个边,每条边有流量上界和下界,问能否使这n个点形成一个流量循环,每个点流入等于流出,每条边都在界限之内。
典型的有上下界无源汇网络流。
法一:
建立源点 s s s 和汇点 t t t , 对于图中每条边 < u , v > <u, v> <u,v> ,拆成如下三条:
法二:
建立源点 s s s 和汇点 t t t ,对于每条边建立 < u , v > <u,v> <u,v> 容量为 r − l r-l r−l 的边。此外,对于图中每个点,令 d [ i ] = ∑ i 节 点 所 有 入 流 下 界 和 − ∑ i 节 点 所 有 出 流 下 界 和 d[i] = \sum i节点所有入流下界和 - \sum i节点所有出流下界和 d[i]=∑i节点所有入流下界和−∑i节点所有出流下界和 。
若 d [ i ] > 0 d[i] > 0 d[i]>0, 建立 < s , i > <s,i> <s,i> 容量为 d [ i ] d[i] d[i] 的边。
若 d [ i ] < 0 d[i] < 0 d[i]<0 ,建立 < i , t > <i,t> <i,t> 容量为 − d [ i ] -d[i] −d[i] 的边。
然后跑 s s s 到 t t t 的最大流,若附加边全部满流,即 m a x f l o w = ∑ d [ i ] > 0 maxflow = \sum d[i] >0 maxflow=∑d[i]>0之和,存在可行流。每条边流量同法一。
其实法一和法二本质是一样的,但法二建立的边更少,速度更快。
#include
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 205;
const int MAXM = 100005;
const int INF=0x3f3f3f3f;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
return x*f;
}
struct Edge{
int to,next,cap,flow;
int id;
}edge[MAXM];
int tot,head[MAXN];
int Q[MAXN],cur[MAXN],dep[MAXN];
int n,m,S,T,N,to[MAXN];
void init(){
tot = 2;
memset(head,-1,sizeof head);
}
void addedge(int u, int v, int w, int id, int rw = 0) {
edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0; edge[tot].id = id;
edge[tot].next = head[u]; head[u] = tot++;
edge[tot].to = u; edge[tot].cap = rw; edge[tot].flow = 0; edge[tot].id = -1;
edge[tot].next = head[v]; head[v] = tot++;
}
bool bfs(int s,int t,int n){
int Front = 0, tail = 0;
memset(dep,-1,sizeof(dep[0])*(n+1));
dep[s] = 0;
Q[tail++] = s;
while(Front < tail){
int u = Q[Front++];
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap > edge[i].flow && dep[v] == -1){
dep[v] = dep[u]+1;
if(v==t) return true;
Q[tail++] = v;
}
}
}
return false;
}
int dfs(int u,int f){
if(u==T) return f;
int used = 0, rflow = 0;
for(int i=cur[u];i!=-1;i=edge[i].next){
cur[u] = i;
int v = edge[i].to, w = edge[i].cap - edge[i].flow;
if (w>0 && dep[v] == dep[u]+1){
if((rflow=dfs(v,min(w,f-used)))){
used+=rflow;
edge[i].flow += rflow;
edge[i^1].flow -= rflow;
if(used == f) break;
}
}
}
if(!used) dep[u] = -1;
return used;
}
int dinic(int s,int t,int n){
int maxflow = 0;
while(bfs(s,t,n)){
for(int i=0;i<=n;i++) cur[i] = head[i];
maxflow += dfs(s,INF);
}
return maxflow;
}
int low[MAXM], d[MAXN], id[MAXM];
int main(){
// freopen("cooling.in","r",stdin);
// freopen("cooling.out","w",stdout);
int kase;
kase = read();
while(kase--) {
n = read(); m = read();
init();
for(int i=0;i<=n;i++) d[i] = 0;
for(int i=0;i<=m;i++) id[i] = 0;
S = 0, T = n + 1, N = n + 1;
for(int i=1;i<=m;i++) {
int u,v,l,r; u = read(); v = read(); l = read(); r = read();
addedge(u,v,r-l,i);
low[i] = l;
d[u] -= l; d[v] += l;
id[i] = tot-2;
}
int sum = 0;
for(int i=1;i<=n;i++) {
if(d[i] > 0 ) {
sum += d[i];
addedge(S,i,d[i],-1);
}else if(d[i] < 0 ) {
addedge(i,T,-d[i],-1);
}
}
if(dinic(S,T,N) == sum) {
puts("YES");
for(int i=1;i<=m;i++) {
printf("%d\n",low[i] + edge[id[i]].flow);
}
}else {
puts("NO");
}
puts("");
}
return 0;
}