因为是有源汇所以设源点为 s,汇点为 t。
有源汇有上下界最大流:
- 连接一条 t 指向 s 的边,容量为 INF。
- 通过上述步骤,现在图变成了无源汇网络。
- 引入超级源点 S,超级汇点 T。
- 连接一条 S 到网络中所有的点的边,容量为 。
- 连接一条网络中所有的点到 S的边,容量为 。(关于d的定义,参考无源汇有上下界可行流 配题(HDU 4940))。
- 网络中边的容量为上界减去下界。
- 计算一次超级源点 S 到超级汇点 T 的最大流,得出无源有上下界可行流是否存在。(关于可行流是否存在,参考无源汇有上下界可行流 配题(HDU 4940))
- 在存在可行流的前提情况下,有源汇有上下界最大流 = 可行流 + s 到 t 的最大流,其代码过程是不删除 t -> s这条边,因为其反向边的流量就是可行流的大小,所以直接在计算过无源汇有上下界可行流的残留网络上计算 s 到 t 的最大流即可。
有源汇有上下界最小流:
- 首先求最小流那么一定是有下界的,如果没有上界可以用INF来代替上界。
- 连接一条 t 指向 s 的边,容量为 INF。
- 通过上述步骤,现在图变成了无源汇网络。
- 引入超级源点 S,超级汇点 T。
- 连接一条 S 到网络中所有的点的边,容量为 。
- 连接一条网络中所有的点到 S的边,容量为 。
- 网络中边的容量为上界减去下界。
- 计算一次超级源点 S 到超级汇点 T 的最大流,得出无源有上下界可行流是否存在。
- 在存在可行流的前提情况下,首先保存可行流,可行流大小为 t 到 s 这条边的反向边流量,那么,有源汇有上下界最小流 = 可行流流量 - t 到 s 的最大流(计算 t 到 s 的最大流的时候需要将 s 到 t 及其反向边的流量设置为 0)。
配题:HDU 3157,是一个有源汇有上下界最小流问题。
题意:(题目本意读一下就行了,电路板通电,让所有元件都工作,每个元件工作需要有一个最低电流,这里直接给抽象过来的题意)多组输入,给出N,M,分别表示除了起点“+”和终点“-”以外有 N 个点,有 M 个边,之后有 M 行,表示 M 条边,每一行有三个输入,p、n、i,表示有一条边从 p 指向 n 其容量下限为 i。求能让这个电路板上所有元件都有点的最小电量?没法都工作就输出impossible。
思路:没有什么抽象的东西,典型有源汇有上下界最小流问题,由于图中边没有流量上界,所以随便设置一个INF就可以了。如果没有可行流,就是输出“impossible”,如果有就输出最小流即可,具体思路上面已经给出,在代码中有充分体现。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 200+10;
const int INF = 0x7fffffff;
int n, m;
int source, sink;
int F_source, F_sink;
int super_line_id;
int d[maxn];
int sb_node[maxn], sb_edge[maxn], depth[maxn];
struct EDGE
{
int u, v;
int flow;
EDGE(int u, int v, int flow): u(u), v(v), flow(flow){}
};
vector<int>graph[maxn];
vector<EDGE>edge;
void init(int lft, int rht)
{
memset(d, 0, sizeof(d));
for (int i = lft; i <= rht; i++)
{
graph[i].clear();
}
edge.clear();
}
void add_edge(int u, int v, int flow)
{
edge.push_back(EDGE(u, v, flow));
edge.push_back(EDGE(v, u, 0));
int cnt = edge.size();
graph[u].push_back(cnt-2);
graph[v].push_back(cnt-1);
}
int Min(int x, int y)
{
if (x < y) return x;
else return y;
}
bool spfa(int s, int t)
{
queue<int>q;
while (!q.empty()) q.pop();
memset(depth, 0, sizeof(depth));
depth[s] = 1;
q.push(s);
while (!q.empty())
{
int cur_node = q.front();
q.pop();
for (int i = 0; i < graph[cur_node].size(); i++)
{
int id = graph[cur_node][i];
int next_node = edge[id].v;
int flow = edge[id].flow;
if (depth[next_node] == 0 && flow > 0)
{
depth[next_node] = depth[cur_node] + 1;
sb_node[next_node] = cur_node;
sb_edge[next_node] = id;
q.push(next_node);
}
}
}
if (depth[t] == 0)
{
return false;
}
else
{
return true;
}
}
int dinic(int s, int t)
{
int res = 0;
while (spfa(s, t))
{
int cut_flow = INF;
for (int cur_node = t; cur_node != s; cur_node = sb_node[cur_node])
{
int id = sb_edge[cur_node];
cut_flow = Min(cut_flow, edge[id].flow);
}
res += cut_flow;
for (int cur_node = t; cur_node != s; cur_node = sb_node[cur_node])
{
int id = sb_edge[cur_node];
edge[id].flow -= cut_flow;
edge[id^1].flow += cut_flow;
}
}
return res;
}
void show_flow(int s, int t)
{
// bool vis[maxn];
// queue<int>q;
//
// memset(vis, false, sizeof(vis));
// while (!q.empty()) q.pop();
//
// vis[s] = true;
// q.push(s);
//
// while (!q.empty())
// {
// int cur_node = q.front();
// q.pop();
// cout<< "cur_node:"<< cur_node<< endl;
// for (int i = 0; i < graph[cur_node].size(); i++)
// {
// int id = graph[cur_node][i];
// int next_node = edge[id].v;
// int flow = edge[id].flow;
// if (!vis[next_node])
// {
// cout<< "next_node:"<< next_node<< " flow:"<< edge[id^1].flow<< endl;
// vis[next_node] = true;
// q.push(next_node);
// }
// }
// }
for (int i = s; i <= t; i++)
{
for (int j = 0; j < graph[i].size(); j++)
{
int id = graph[i][j];
int v = edge[id].v;
if (v == i) continue;
cout<< "<"<< i<< ","<< v<< ">"<< "flow="<< edge[id].flow<< " backflow="<< edge[id^1].flow<< endl;
}
}
}
int main()
{
while (cin>> n>> m)
{
if (n == 0 && m == 0)
{
break;
}
int judge_flow = 0;
init(0, n+5);
source = 0; // pos
sink = n+1; // neg
F_source = n+2; // super source
F_sink = n+3; // super sink
for (int i = 1; i <= m; i++)
{
char s1[2], s2[2];
int flow;
int u, v;
scanf("%s%s%d", s1, s2, &flow);
if (s1[0] == '+')
{
u = source;
}
else if (s1[0] == '-')
{
u = sink;
}
else
{
sscanf(s1, "%d", &u);
}
if (s2[0] == '+')
{
v = source;
}
else if (s2[0] == '-')
{
v = sink;
}
else
{
sscanf(s2, "%d", &v);
}
add_edge(u, v, INF-flow);
d[u] -= flow;
d[v] += flow;
}
add_edge(sink, source, INF);
int mark = edge.size()-2;
for (int i = source; i <= sink; i++)
{
if (d[i] > 0)
{
add_edge(F_source, i, d[i]);
judge_flow += d[i];
}
else if (d[i] < 0)
{
add_edge(i, F_sink, -d[i]);
}
}
int tmp = dinic(F_source, F_sink);
int feasible_flow = edge[mark^1].flow;
if (tmp != judge_flow)
{
cout<< "impossible"<< endl;
}
else
{
edge[mark].flow = 0;
edge[mark^1].flow = 0;
int max_flow = dinic(sink, source);
cout<< feasible_flow - max_flow<< endl;
}
}
return 0;
}