上下界网络流,可以去看看胡伯涛的一篇图论的总结。
需要注意的是,数据中有一个点#12,它的最小流是负的(讨论里有一个样例来说明),而题目要求必须大于等于0,所以有点变化。
然后,网络流的实现部分是用的算法导论上讲的Relabel-To-Front实现,我已经把它做成了一个模板。
相比于ISAP,Relabel-To-Front的理论时间复杂度更低,但是ISAP通常很快,甚至有时能和HLPP相媲美,不过我还是选择了Relabel-To-Front。不管怎样,它都比以前学的EK快多了。
CODE:
/*
AUTHOR: Su Jiao
DATE: 2010-7-2
DESCRIPTION:
$DESCRIPTION
*/
//Test#1: USACO Training ditch
namespace sj
{
template<int MAXV,int MAXEDGE>
class Relabel_To_Front
{
public:
struct rtf_edge{int v,c;rtf_edge* next;rtf_edge* back;};
struct rtf_list{int u;rtf_list* next;};
typedef struct rtf_edge* edge_pointer;
typedef struct rtf_list* list_pointer;
typedef struct rtf_edge edge;
typedef struct rtf_list list;
static edge_pointer adj[MAXV];
static edge_pointer current[MAXV];
static int e[MAXV];
static int h[MAXV];
static int hn[MAXV*2];
void add_list(int u,list_pointer& tail)
{
static list pool[MAXV];
static list_pointer top=pool;
tail->u=u;
tail->next=top++;
tail=tail->next;
}
static int V,E;
static int s,t;
void add_edge(int u,int v,int c)
{
static edge pool[MAXEDGE];
static edge_pointer top=pool;
top->v=v;
top->c=c;
top->next=adj[u];
adj[u]=top++;
top->v=u;
top->c=0;
top->next=adj[v];
adj[v]=top++;
adj[u]->back=adj[v];
adj[v]->back=adj[u];
}
#define min(a,b) (a)<(b)?(a):(b)
#define relabel(_u)\
{\
/*GAP*/\
hn[h[(_u)]]–;\
if (hn[h[(_u)]]==0&&0<h[(_u)]&&h[(_u)]<V)\
{\
for (int i=0;i<V;i++)\
if (i!=s&&h[(_u)]<h[i]&&h[i]<V+1)\
{\
hn[h[i]]–;\
h[i]=V+1;\
hn[h[i]]++;\
}\
}\
\
h[(_u)]=V*2-1;\
for (edge_pointer i=adj[(_u)];i;i=i->next)\
if (i->c&&h[(_u)]>h[i->v]+1)\
h[(_u)]=h[i->v]+1;\
\
/*GAP*/\
hn[h[(_u)]]++;\
}
#define push(_u,_v)\
{\
int df=min(e[(_u)],(_v)->c);\
e[(_u)]-=df;\
e[(_v)->v]+=df;\
(_v)->c-=df;\
(_v)->back->c+=df;\
}
#define discharge(_u)\
{\
while (e[(_u)])\
{\
if (!current[(_u)])\
{\
relabel((_u));\
current[(_u)]=adj[(_u)];\
}\
else if (h[(_u)]==h[current[(_u)]->v]+1\
&¤t[(_u)]->c)\
{\
push((_u),current[(_u)]);\
}\
else current[(_u)]=current[(_u)]->next;\
}\
}
int relabel_to_front(void (*build_network)(Relabel_To_Front*))
{
build_network(this);
for (edge_pointer i=adj[s];i;i=i->next)
{
e[s]-=i->c;
e[i->v]+=i->c;
i->back->c=i->c;
i->c=0;
}
h[s]=V;
/*GAP*/
hn[0]=V-1;
hn[V]=1;
list L;
list_pointer head=&L,tail=&L;
for (int i=0;i<V;i++)
if (i!=s&&i!=t)
add_list(i,tail);
for (int i=0;i<V;i++) current[i]=adj[i];
list_pointer pre=0,u=head;
while (u!=tail)
{
int old_h=h[u->u];
discharge(u->u);
if (h[u->u]>old_h)
if (pre)
{
pre->next=u->next;
u->next=head;
head=u;
}
pre=u;
u=u->next;
}
return e[t];
}
#undef min
#undef relabel
#undef push
#undef discharge
};
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::V;
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::E;
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::s;
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::t;
template<int MAXV,int MAXEDGE>
typename Relabel_To_Front<MAXV,MAXEDGE>::edge_pointer
Relabel_To_Front<MAXV,MAXEDGE>::adj[MAXV];
template<int MAXV,int MAXEDGE>
typename Relabel_To_Front<MAXV,MAXEDGE>::edge_pointer
Relabel_To_Front<MAXV,MAXEDGE>::current[MAXV];
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::e[MAXV];
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::h[MAXV];
template<int MAXV,int MAXEDGE>
int Relabel_To_Front<MAXV,MAXEDGE>::hn[MAXV*2];
}
#include <stdio.h>
#include <string.h>
using namespace sj;
#define MAXN 100
#define MAXM 10000
typedef Relabel_To_Front<MAXN+2,4*(MAXN+2)*(MAXN+2)> RTF;
int N,M;
int U[MAXM],V[MAXM],Z[MAXM],C[MAXM];
RTF rtf;
int total;
int first_flow;
RTF::edge* edg1[MAXM];
RTF::edge* edg2[MAXM];
RTF::edge* edg3[MAXM];
RTF::edge* edg4;
void build_network(RTF* that)
{
scanf(“%d%d”,&N,&M);
that->V=N+2;
that->s=0;
that->t=N+1;
for (int i=0;i<M;i++)
{
scanf(“%d%d%d%d”,U+i,V+i,Z+i,C+i);
if (C[i])
{
that->add_edge(that->s,V[i],Z[i]);
that->add_edge(U[i],that->t,Z[i]);
total+=Z[i];
edg1[i]=that->adj[that->s];
edg2[i]=that->adj[U[i]];
}
else
{
that->add_edge(U[i],V[i],Z[i]);
edg3[i]=that->adj[U[i]];
}
}
const int oo=~(1<<31);
that->add_edge(N,1,oo);
edg4=that->adj[N];
}
void rebuild_network(RTF* that)
{
first_flow=edg4->back->c;
edg4->c=edg4->back->c=0;
for (int i=0;i<M;i++)
if (C[i])
{
edg1[i]->c=edg1[i]->back->c=0;
edg2[i]->c=edg2[i]->back->c=0;
}
memset(RTF::e,0,sizeof(RTF::e));
memset(RTF::h,0,sizeof(RTF::h));
memset(RTF::hn,0,sizeof(RTF::hn));
that->s=0;
that->t=1;
that->V=N+1;
that->add_edge(that->s,N,first_flow);
}
int main()
{
int flow=rtf.relabel_to_front(build_network);
if (flow!=total) printf(“Impossible\n”);
else
{
int flow=rtf.relabel_to_front(rebuild_network);
printf(“%d\n”,first_flow-flow);
for (int i=0;i<M;i++)
if (C[i]) printf(“%d%c”,Z[i],i+1==M?’\n’:’ ‘);
else printf(“%d%c”,edg3[i]->back->c,i+1==M?’\n’:’ ‘);
}
return 0;
}