题意:
给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质。
并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li。
例如:
46(4个点,6个pipe)
12 1 3 (1->2上界为3,下界为1)
23 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3
(LOJ 115更加直白,要求是一样的)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
struct edge{
int to,cap,rev,id;
};
vector<edge>G[210];
int level[205],iter[205],cha[205],lower[200005],cur[205];
void addedge(int from,int to,int cap)
{
G[from].push_back(edge{to,cap,(int)G[to].size()});
G[to].push_back(edge{from,0,(int)G[from].size()-1});//反向容量为0!!
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int>que;
level[s]=0;que.push(s);
while(!que.empty()){
int t=que.front();que.pop();
for(int i=0;i<G[t].size();i++){
edge e=G[t][i];
if(e.cap>0&&level[e.to]<0){
level[e.to]=level[t]+1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t)return f;
for(int&i=iter[v];i<G[v].size();i++){//注意传引用!
edge&e=G[v][i];
if(e.cap>0&&level[v]<level[e.to]){
int d=dfs(e.to,t,min(f,e.cap));
if(d>0){
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;//不要漏了这个,很多时候可能是无法增广的
}
int maxflow(int s,int t){
int flow=0;
for(;;){
bfs(s);
if(level[t]<0)return flow;
memset(iter,0,sizeof(iter));
int f;
while(f=dfs(s,t,0x7f7f7f7f))
flow+=f;
}
}
struct ans{
int id,cap;
bool operator<(const ans v)const{
return id<v.id;
}
};
int main() {
int n, m, i, j, k;
cin >> n >> m;
for (i = 1; i <= m; i++) {
int a, b, d;
scanf("%d%d%d%d", &a, &b, &lower[i], &d);//每条边的下界
cur[b] += lower[i];//统计每个点的下界情况
cur[a] -= lower[i];
addedge(a, b, d - lower[i]);
G[a].back().id = i;//记录边的id
}
int sum = 0;
for (i = 1; i <= n; i++) {
if (cur[i] > 0) {
addedge(0, i, cur[i]);
sum += cur[i];
} else if (cur[i] < 0) {
addedge(i, 201, -cur[i]);
}
}
int flow = maxflow(0, 201);
if (flow != sum) {
cout << "NO" << endl;
return 0;
}
cout << "YES" << endl;
vector<ans> as;//存答案
for (i = 1; i <= n; i++) {
for (j = 0; j < G[i].size(); j++) {
edge e = G[i][j];
if (!e.id)continue;//注意反向边以及连向汇点源点的边是没有ID的,也就是ID是0;
as.push_back(ans{e.id, G[e.to][e.rev].cap + lower[e.id]});//这条边的反向边的容量+这条边的下界
}
}
sort(as.begin(), as.end());
for (i = 0; i < as.size(); i++) {
printf("%d\n", as[i].cap);
}
return 0;
}