题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314
建图:
首先,建立一个超级源点s和超级汇点t。
然后,把所有原图中的边都加入到建立的新图中,容量为上限间下限。
再后,计算出一个d[i],表示编号为 i 的点所有流入的下限流量的和 减去 该点所有留出的下限流量和;如果d[i] > 0,那么就连一条从 s 到 i 容量为 d[i] 的边;如果d[i] < 0,那么就从 i 到 t 连一条容量为 -d[i] 的边;如果 d[i] == 0,就不用连边。
最后,计算 s 到 t 最大流。
注意,输出的时候只输出原图中的边,流量为计算出的流量加上流量下限。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 300
#define maxm 20000
#define INF (1<<31)-1
using namespace std;
int l[maxn] = {0};
struct Edge
{
int from, to, cap, flow;
int weight;
Edge(int u, int v, int c, int f, int w):
from(u), to(v), cap(c), flow(f), weight(w) {}
};
struct Dinic
{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int p[maxn];
int a[maxn];
int num_Edge[maxm];
void init(int n, int m)
{
this->n = n;
this->m = m;
this->s = 0;
this->t = n+1;
for (int i=0; i<n; i++)
{
G[i].clear();
}
edges.clear();
}
void addEdge(int from, int to, int cap, int w = 1)
{
edges.push_back(Edge(from, to, cap, 0, w));
edges.push_back(Edge(to, from, 0, 0, w));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
num_Edge[n] = m-2;
}
int spfa()
{
memset(vis,0,sizeof(vis)); vis[s] = true;
for (int i=0; i<=t; i++) d[i] = INF; d[s] = 0;
p[s] = 0; a[s] = INF;
/*for (int i=0; i<=n; i++)
cout<<d[i]<<' ';*/
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = true;
while (!Q.empty())
{
int x = Q.front();
Q.pop();
vis[x] = false;
for (int i=0; i<G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if (e.cap>e.flow && d[e.to] > d[x]+e.weight)
{
d[e.to] = d[x]+e.weight;
p[e.to] = G[x][i];
a[e.to] = min(a[x], e.cap-e.flow);
if (!vis[e.to])
{
Q.push(e.to);
vis[e.to] = true;
}
}
}
}
if (d[t] == INF)
return 0;
int u = t;
while (u != s)
{
Edge e = edges[p[u]];
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return a[t];
}
int maxFlow()
{
int flow = 0;
while (true)
{
int f = spfa();
if (!f)
break;
flow += f;
}
return flow;
}
void print(int m)
{
bool flag = true;
for (int i=0; i<G[s].size(); i++)
{
Edge e = edges[G[s][i]];
if (e.flow < e.cap)
{
flag = false;
break;
}
}
if (flag)
{
cout<<"YES"<<endl;
for (int i=1; i<=m; i++)
cout<<edges[(i-1)*2].flow + l[i]<<endl;
}
else
cout<<"NO"<<endl;
}
};
int main()
{
int t;
cin>>t;
while (t > 0)
{
t--;
int n, m;
Dinic a;
scanf("%d%d",&n,&m);
a.init(n,m);
int d[maxn] = {0};
for (int i=1; i<=m; i++)
{
int u, v, c;
scanf("%d%d%d%d",&u,&v,&l[i],&c);
a.addEdge(u,v,c-l[i]);
d[u] -= l[i];
d[v] += l[i];
}
for (int i=1; i<=n; i++)
{
if (d[i] > 0)
a.addEdge(0,i,d[i]);
else if (d[i] < 0)
a.addEdge(i,n+1,-d[i]);
}
int ans = a.maxFlow();
a.print(m);
if (t > 0)
cout<<endl;
}
return 0;
}