循环流无视掉即可。因为入出点相连就是循环的了。
构图:
a->q 容量为c,下界为b,改为a->q容量为c-b,同时记录从a出去的下界流量out[a]+=b, 进入q的下界流量in[q]+=b
最后扫描整个网络图,如果in[i]>out[i],那么就建立超级S,S->i的边,容量为in[i]-out[i]。
否则简历超级T,i->T的容量为out[i]-in[i]即可。
接下来就是套板子,顺便略加修改。
一个修改是,因为这题要输出原来每个边的流量,所以建边的时候,要记录每个边的编号,所以要导入id
void add_edge(int from, int to, int cap, int id) {
edges.push_back((Edge){from, to, cap, 0, id});
edges.push_back((Edge){to, from, 0, 0, id});
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
读入也略加修改即可
for (int i = 1; i <= M; ++ i)
{
int s,t,b,c;
scanf("%d%d%d%d", &s, &t, &b, &c);
liu[i]=b;
isap.add_edge(s,t,c-b,i);
chu[s]+=b;
jin[t]+=b;
}
for (int i = 1; i <= n; ++ i)
{
if (jin[i]>chu[i])
isap.add_edge(0, i, jin[i]-chu[i], 0);
else isap.add_edge(i, n + 1, chu[i] - jin[i], 0);
}
最后遍历所有的边,如果那个边的编号为0,就是新添加的边,不算。
否则,如果cap为0,则为反向边,我们需要所有正向边中的flow的数值。
然后贴上板子AC这题即可。
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#include <tr1/unordered_map>
using std::tr1::unordered_map;
//using std::setiosflags;
//using std::setprecision;
using std::sort;
using std::max;
using std::min;
using std::cout;
using std::stack;
using std::cin;
using std::endl;
using std::swap;
using std::pair;
using std::vector;
using std::set;
using std::map;
using std::multiset;
using std::unique;
using std::queue;
using std::greater;
using std::string;
using std::priority_queue;
using std::lower_bound;//返回第一个不小于
using std::upper_bound;//返回第一个大于
using std::max_element;
using std::min_element;
using __gnu_pbds::pairing_heap_tag;
#define x first
#define y second
#define Hash unordered_map
#define clr(x) memset(x,0,sizeof(x))
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef __gnu_pbds::priority_queue<pii, greater<pii>, pairing_heap_tag> Heap;//小根堆
typedef Heap::point_iterator Hit;
const Hit null;
const double PI = acos(-1);
const LL LINF = 0x3f3f3f3f3f3f3f3fll;//4e18
const int INF = 0x3f3f3f3f;//1e9
const double eps = 1e-10;
#define prln(x) cout<<#x<<" = "<<x<<endl
#define pr(x) cout<<#x<<" = "<<x<<" "
const int maxn = 205;
int n, M;
int liu[maxn*maxn];
//调用方法:
//init(n) 初始化 n 为节点数
//clear_flow() 清空所有边的流量
//add_edge(from, to, cap) 添加边from -> to 容量为cap
//maxflow(s, t) 返回s->t的最大流
//void mincut(vector<int>& ans) // 调用完maxflow后才可以用,ans里面存最小割
//print() 打印整张图,调试用
struct Edge { int from, to, cap, flow, id; };
struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
int p[maxn]; // 可增广路上的上一条弧
int num[maxn]; // 距离标号计数
void add_edge(int from, int to, int cap, int id) {
edges.push_back((Edge){from, to, cap, 0, id});
edges.push_back((Edge){to, from, 0, 0, id});
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(t);
vis[t] = 1;
d[t] = 0;
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]^1];
if(!vis[e.from] && e.cap > e.flow) {
vis[e.from] = 1;
d[e.from] = d[x] + 1;
q.push(e.from);
}
}
}
return vis[s];
}
void init(int n) {
this->n = n;
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
void clear_flow() {
for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
}
int augment() {
int x = t, a = INF;
while(x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap-e.flow);
x = edges[p[x]].from;
}
x = t;
while(x != s) {
edges[p[x]].flow += a;
edges[p[x]^1].flow -= a;
x = edges[p[x]].from;
}
return a;
}
int maxflow(int s, int t) {//找到的最大流大于need就停止,如果没有限制,删去含有need的地方
this->s = s; this->t = t;
int flow = 0;
bfs();
memset(num, 0, sizeof(num));
for(int i = 0; i < n; i++) num[d[i]]++;
int x = s;
memset(cur, 0, sizeof(cur));
while(d[s] < n) {
if(x == t) {
flow += augment();
//if(flow >= need) return flow;
x = s;
}
int ok = 0;
for(int i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance
ok = 1;
p[e.to] = G[x][i];
cur[x] = i; // 注意
x = e.to;
break;
}
}
if(!ok) { // Retreat
int m = n-1; // 初值注意
for(int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow) m = min(m, d[e.to]);
}
if(--num[d[x]] == 0) break;//gap优化
num[d[x] = m+1]++;
cur[x] = 0; // 注意
if(x != s) x = edges[p[x]].from;
}
}
return flow;
}
void mincut(vector<int>& ans) { // 调用完maxflow后才可以用,ans里面存最小割
bfs();
for(int i = 0; i < edges.size(); i++) {
Edge& e = edges[i];
if(!vis[e.from] && vis[e.to] && e.cap > 0) ans.push_back(i);
}
}
void print() {
printf("Graph:\n");
for(int i = 0; i < edges.size(); i++)
printf("%d->%d, %d, %d\n", edges[i].from, edges[i].to , edges[i].cap, edges[i].flow);
}
void doit()
{
int flag=1;
for (int i = 0; i <= n + 1; ++ i)
{
for (auto x : G[i])
{
int s = edges[x].from;
int t = edges[x].to;
int c = edges[x].cap;
int f = edges[x].flow;
if (s==0)
{
if (c!=f) flag=0;
continue;
}
if (t==n+1)
{
if (c!=f) flag=0;
continue;
}
if (c==0) continue;
liu[edges[x].id] += f;
}
}
if (flag)
{
printf("YES\n");
for (int i = 1; i <= M; ++i)
printf("%d\n", liu[i]);
}
else printf("NO\n");
}
} isap;
int jin[maxn], chu[maxn];
int main()
{
int T=0;
while (~scanf("%d%d", &n, &M))
{
memset(chu,0,sizeof(chu));
memset(jin, 0, sizeof(jin));
isap.init(n+2);
for (int i = 1; i <= M; ++ i)
{
int s,t,b,c;
scanf("%d%d%d%d", &s, &t, &b, &c);
liu[i]=b;
isap.add_edge(s,t,c-b,i);
chu[s]+=b;
jin[t]+=b;
}
for (int i = 1; i <= n; ++ i)
{
if (jin[i]>chu[i])
isap.add_edge(0, i, jin[i]-chu[i], 0);
else isap.add_edge(i, n + 1, chu[i] - jin[i], 0);
}
isap.maxflow(0, n+1);
isap.doit();
}
return 0;
}