一.题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314
二,题目大意:给一个无汇源点,流量有上下界限的图,求出是否有可行流,如果有,输出每条管子上的最大流。
三.思路:首先判断有无可行流,由于流量有上下界,于是,自然而然想到了每条弧用上界减去下界,但是这样违反了流量守恒(流入一个节点的流等于流出的)。
比如说:(u,v)上下界为(1,3), (v, q)上下界为(3,4)一条边减去2,另一条边减去了1,减去的流量不相等,相当于1的流量积累在v。于是我们可以想到建立源点、汇点来导流。
具体建图如下:
1.记录每个点的D = (每条进入它的弧的下界) 减去 (由它出发的弧的下界)。如果大于0,得到的就是积累在本节点的流量,于是建立一个汇点,把流导给它。容量为D。如果小于0,得到的就是本节点所需要进入的流量,建立一个源点s,跟它相连,容量为-D。
2.当然原来容量网络的每条弧保持一样,容量变为上界 减去 下界。
对于构造出来的图我们叫它伴随网络,(当然它的每条弧下界都为0)只有伴随网络的最大流使得从源点S出发,每条弧都满了(此时连到T的弧也一定会满),原来网络才有可行流。而本题还要求原容量网络中每条弧的可行流的流量,其实它只等于伴随网络中所对应的弧的流量加上每条弧流量的下界。而对于邻接表建图的话,伴随网络中所对应的弧的流量,就是第2*i条边的反向弧最后的流量。也就是2*i^1。
四.代码:
#include
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f,
MAX_N = 209;
class Dinic
{
public:
struct Edge
{
int v, w, next;
};
int cnt, head[MAX_N], dist[MAX_N], s, t;
Edge edges[MAX_N*MAX_N];
void init(int is, int it)
{
cnt = 0;
s = is, t = it;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int weight)
{
edges[cnt] = (Edge){v, weight, head[u]};
head[u] = cnt++;
edges[cnt] = (Edge){u, 0, head[v]};
head[v] = cnt++;
}
bool BFS()
{
int i, cur;
queue que;
que.push(s);
memset(dist, -1, sizeof(dist));
dist[s] = 0;
while(!que.empty()){
cur = que.front();
que.pop();
for(i = head[cur]; i != -1; i = edges[i].next)
if(-1 == dist[edges[i].v] && edges[i].w){
dist[edges[i].v] = dist[cur] + 1;
que.push(edges[i].v);
}
}
return dist[t] != -1;
}
int DFS(int start, int curFlow)
{
if(start == t)
return curFlow;
int i, minFlow = 0, v, temp;
for(i = head[start]; i != -1; i = edges[i].next){
v = edges[i].v;
if(dist[start] == dist[v] - 1 && edges[i].w > 0){
temp = DFS(v, min(edges[i].w, curFlow));
edges[i].w -= temp;
edges[i^1].w += temp;
curFlow -= temp;
minFlow += temp;
if(0 == curFlow)
break;
}
}
if(0 == minFlow)
dist[start] = -2;
return minFlow;
}
int maxFlow()
{
int res = 0;
while(BFS()){
res += DFS(s, INF);
}
return res;
}
}G;
int nodeNum, edgeNum,
cnt[MAX_N];
int main()
{
//freopen("in.txt", "r", stdin);
int sum, i, j, test, u, v, down[MAX_N*MAX_N], up, s, t;
scanf("%d", &test);
while(test--){
scanf("%d%d", &nodeNum, &edgeNum);
s = nodeNum + 1, t = nodeNum + 2;
G.init(s, t);
memset(cnt, 0, sizeof(cnt));
for(i = 0; i < edgeNum; i++){
scanf("%d%d%d%d", &u, &v, &down[i], &up);
cnt[u] += down[i], cnt[v] -= down[i];
G.addEdge(u, v, up - down[i]);
}
sum = 0;
for(i = 1; i <= nodeNum; i++){
if(cnt[i] > 0){
G.addEdge(i, t, cnt[i]);
sum += cnt[i];
}
else if(cnt[i] < 0)
G.addEdge(s, i, -cnt[i]);
}
if(sum == G.maxFlow()){
printf("YES\n");
for(i = 0; i < edgeNum; i++)
printf("%d\n", down[i] + G.edges[(2*i)^1].w);
printf("\n");
}
else
printf("NO\n\n");
}
return 0;
}