(1)、无源无汇有容量下界的可行流问题;
建立附加源s和附加汇t,然后对弧进行改造:首先添加弧t->s容量为无穷大;然后把每条弧(u,v)拆成3条:s->v(容量为u,v的下界),u->t(容量为u,v下届),u ->v(容量为u,v上界减去u,v下界)
求改造后的网络的最大流即可。当且仅当所有附加弧(与s和t相连的边)满载时原网络有可行流。且原网络中每条边(u,v)的流量的等于改造后的网络中(u,v)的流量加上(u,v)的下界;
ZOJ2314 无源无汇可行流模板题目;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<stack>
#define ll long long
#define MAX 500
#define eps 1e-8
#define INF 100000000
using namespace std;
struct Node{
int l,c;
}F[MAX][MAX];
struct Edge{
int from, to,cap,flow;
};
vector<int>G[MAX],T[MAX]; //T用来记录G的转置,用于下面逆向bfs遍历图
vector<Edge>edges;
int n;
void init(){
for (int i=0; i<MAX; i++){
G[i].clear();
T[i].clear();
}
edges.clear();
}
void addEdge(int from, int to, int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
int k = edges.size();
G[from].push_back(k-2);
G[to].push_back(k-1);
T[to].push_back(from);
}
int d[MAX];
void bfs(int s, int t){
bool vis[MAX];
queue<int>q;
memset(vis,false,sizeof(vis));
q.push(s);
d[s] = 0;
vis[s] = true;
while (!q.empty()){
int u = q.front();
q.pop();
for (int i=0; i<T[u].size(); i++){
int v = T[u][i];
if (!vis[v]){
d[v] = d[u] + 1;
vis[v] = true;
q.push(v);
}
}
}
}
int p[MAX],num[MAX],cur[MAX];
int Augment(int s, int t){
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){
int flow = 0;
bfs(t,s); //逆向bfs
memset(num,0,sizeof(num));
for (int i=0; i<=n; i++) num[d[i]]++; //注意此处i应该对应节点编号
int x = s;
memset(cur,0,sizeof(cur));
while (d[s] < n+1){ //此处d[s]应下于节点数量
if (x == t){
flow += Augment(s,t);
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){
ok = 1;
p[e.to] = G[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if (!ok){
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优化,能使时间复杂度降低100倍左右
num[d[x] = m+1]++;
cur[x] = 0;
if (x != s) x = edges[p[x]].from;
}
}
return flow;
}
int mark[MAX][MAX];
int main(){
int cas,m;
scanf("%d",&cas);
while (cas--){
scanf("%d%d",&n,&m);
int x,y,l,c;
init();
int SS = 0,TT = n+1;
addEdge(TT,SS,INF);
memset(mark,0,sizeof(mark));
for (int i=0; i<m; i++){ //拆边
scanf("%d%d%d%d",&x,&y,&l,&c);
mark[x][y] = 1;
F[x][y] = (Node){l,c};
addEdge(x,y,c-l);
addEdge(x,TT,l);
addEdge(SS,y,l);
}
n = TT;
int ans = Maxflow(SS,TT);
// printf("ans = %d\n",ans);
int ok = 1;
for (int i = 0; i<edges.size(); i++){ //判断是否有可行流
Edge e = edges[i];
if ((e.from == SS || e.to == TT) && e.cap > e.flow){
ok = 0;
break;
}
}
if (ok){
printf("YES\n");
for (int i=0; i<edges.size(); i++){ //求解每条边的流量
Edge e =edges[i];
if (e.flow >= 0 && mark[e.from][e.to] && e.from != SS && e.to != TT)
printf("%d\n",e.flow + F[e.from][e.to].l);
}
}
else printf("NO\n");
if (cas) printf("\n");
}
return 0;
}
有源有汇有上下界的最大流问题;
设源点为s,t;建立附加源点SS,附加汇点TT;
首先连边t->s,容量为无穷大使其转化为无源无汇问题;在对网络中的每一条边(u,v)按照无源无汇中的方法拆成三条边;
最后求一下SS->TT的最大流;可行流存在的条件以及原网络中的每条边的流量同上;
poj2396 有源有汇有上下界的最大流问题;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<stack>
#define ll long long
#define MAX 500
#define eps 1e-8
#define INF 100000000
using namespace std;
struct Node{
int l,c;
}F[MAX][MAX];
struct Edge{
int from, to,cap,flow;
};
vector<int>G[MAX],T[MAX]; //T用来记录G的转置,用于下面逆向bfs遍历图
vector<Edge>edges;
int n;
void init(){
for (int i=0; i<MAX; i++){
G[i].clear();
T[i].clear();
}
edges.clear();
}
void addEdge(int from, int to, int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
int k = edges.size();
G[from].push_back(k-2);
G[to].push_back(k-1);
T[to].push_back(from);
}
int d[MAX];
void bfs(int s, int t){
bool vis[MAX];
queue<int>q;
memset(vis,false,sizeof(vis));
q.push(s);
d[s] = 0;
vis[s] = true;
while (!q.empty()){
int u = q.front();
q.pop();
for (int i=0; i<T[u].size(); i++){
int v = T[u][i];
if (!vis[v]){
d[v] = d[u] + 1;
vis[v] = true;
q.push(v);
}
}
}
}
int p[MAX],num[MAX],cur[MAX];
int Augment(int s, int t){
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){
int flow = 0;
bfs(t,s); //逆向bfs
//printf("ok1\n");
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+1){ //小于节点数目
if (x == t){
flow += Augment(s,t);
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){
ok = 1;
p[e.to] = G[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if (!ok){
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优化,能使时间复杂度降低100倍左右
num[d[x] = m+1]++;
cur[x] = 0;
if (x != s) x = edges[p[x]].from;
}
}
return flow;
}
int l[MAX][MAX],r[MAX][MAX],res[MAX][MAX],a[MAX],b[MAX],m;
bool judge(){
for (int i=1; i<=n; i++)
for (int j=1; j <= m; j++)
if (r[i][j] < l[i][j]) return false;
return true;
}
int main(){
int cas;
scanf("%d",&cas);
while (cas--){
init();
scanf("%d%d",&n,&m);
int s = n+m+1, t = n+m+2;
int SS = 0, TT = n+m+3;
addEdge(t,s,INF); //注意添边t->s(原汇点到原源点),容量为无穷大
for (int i=1; i<=n; i++){
scanf("%d",&a[i]);
addEdge(SS,i,a[i]);
addEdge(s,i,0);
addEdge(s,TT,a[i]);
}
for (int i=1; i <= m; i++){
scanf("%d",&b[i]);
addEdge(SS,t,b[i]);
addEdge(i+n,t,0);
addEdge(i+n,TT,b[i]);
}
int x,y,z;
char st[5];
for (int i=1; i<=n; i++)
for (int j = 1; j<=m; j++){
l[i][j] = 0;
r[i][j] = min(a[i],b[j]);
}
int cc;
scanf("%d",&cc);
while (cc--){
scanf("%d%d%s%d",&x,&y,st,&z);
if (st[0] == '>'){
if (x == 0 && y == 0){
for (int i = 1; i <= n; i++)
for (int j=1; j <= m; j++){
l[i][j] = max(l[i][j],z+1);
}
}
else if (x == 0){
for (int i=1; i<=n; i++){
l[i][y] = max(l[i][y],z+1);
}
}
else if (y == 0){
for (int i=1; i<=m; i++){
l[x][i] = max(l[x][i],z+1);
}
}
else{
l[x][y] = max(l[x][y],z+1);
}
}
else if (st[0] == '<'){
if (x == 0 && y == 0){
for (int i=1; i<=n; i++)
for (int j = 1; j<=m; j++){
r[i][j] = min(r[i][j],z-1);
}
}
else if (x == 0){
for (int i = 1; i<=n; i++){
r[i][y] = min(r[i][y],z-1);
}
}
else if (y == 0){
for (int i = 1; i<=m; i++){
r[x][i] = min(r[x][i],z-1);
}
}
else {
r[x][y] = min(r[x][y],z-1);
}
}
else{
if (x == 0 && y == 0){
for (int i=1; i<=n; i++){
for (int j=1; j<=m; j++){
l[i][j] = max(l[i][j],z);
r[i][j] = min(r[i][j],z);
}
}
}
else if (x == 0){
for(int i = 1; i <= n; i++){
l[i][y] = max(l[i][y],z);
r[i][y] = min(r[i][y],z);
}
}
else if (y == 0){
for (int i = 1; i<=m; i++){
l[x][i] = max(l[x][i],z);
r[x][i] = min(r[x][i],z);
}
}
else {
l[x][y] = max(l[x][y],z);
r[x][y] = min(r[x][y],z);
}
}
}
if (!judge()){
printf("IMPOSSIBLE\n");
if (cas) printf("\n");
continue;
}
for (int i=1; i <= n; i++)
for (int j = 1; j <= m; j++){
addEdge(SS,j+n,l[i][j]);
addEdge(i,j+n,r[i][j] - l[i][j]);
addEdge(i,TT,l[i][j]);
}
int nt = n;
n = TT;
Maxflow(SS,TT);
int ok = 1;
for (int i = 0; i<edges.size(); i++){
Edge e = edges[i];
int u = e.from;
int v = e.to;
if ((u == SS || v == TT) && e.flow != e.cap ){
ok = 0;
break;
}
}
if (!ok){
printf("IMPOSSIBLE\n");
if (cas) printf("\n");
continue;
}
for (int i = 0; i<edges.size(); i++){
Edge e = edges[i];
int u = e.from;
int v = e.to;
res[u][v] = e.flow;
}
for (int i=1; i<=nt; i++){
printf("%d",res[i][1+nt] + l[i][1]);
for (int j = 2; j<=m; j++) printf(" %d",res[i][j+nt]+l[i][j]);
printf("\n");
}
if (cas) printf("\n");
}
return 0;
}
2492

被折叠的 条评论
为什么被折叠?



