模板均来自《挑战程序设计竞赛》
1.最大流算法
2.Dinic算法
//最大流算法Dinic模板
#define INF 0x7fffffff
#define MAX_V 405
//用于表示边的结构体(终点、容量、反向边)
struct edge
{
int to,cap,rev;
};
vector<edge> G[MAX_V];//图的邻接表表示
int level[MAX_V];//顶点到源点的距离标号
int iter[MAX_V];//当前弧,在其之前的边已经没有用了
//向图中增加一条从from到to的容量为cap的边
void add_edge(int from,int to,int cap)
{
G[from].push_back((edge){to,cap,G[to].size()});
G[to].push_back((edge){from,0,G[from].size()-1});
}
//通过BFS计算从源点出发的距离标号
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int> que;
level[s]=0;
que.push(s);
while(!que.empty()){
int v=que.front();
que.pop();
for(int i=0;i<G[v].size();i++){
edge &e=G[v][i];
if(e.cap>0&&level[e.to]<0){
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
}
//通过DFS寻找增广路
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;
}
//求解从s到t的最大流
int max_flow(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,INF))>0){
flow+=f;
}
}
}
//模板
2.二分图匹配
1.代码2
//二分图匹配模板
#define MAX_V 1005
int V;//顶点数
vector<int> G[MAX_V];//图的邻接表表示
int match[MAX_V];//所匹配的顶点
bool used[MAX_V];//DFS中用到的访问标记
//向图中增加一条连接u和v的边
void add_edge(int u,int v)
{
G[u].push_back(v);
G[v].push_back(u);
}
//通过DFS寻找增广路
bool dfs(int v)
{
used[v]=true;
for(int i=0;i<G[v].size();i++){
int u=G[v][i],w=match[u];
if(w<0||!used[w]&&dfs(w)){
match[v]=u;
match[u]=v;
return true;
}
}
return false;
}
//求解二分图的最大匹配
int bipartite_matching()
{
int res=0;
memset(match,-1,sizeof(match));
for(int v=0;v<V;v++){
if(match[v]<0){
memset(used,0,sizeof(used));
if(dfs(v)){
res++;
}
}
}
return res;
}
//二分图匹配模板
3.最小费用流
1.代码1
时间复杂度为O(F|V||E|)(F是流量)
#define INF 0x7fffffff
//最小费用流模板
#define MAX_V 1005
//用于表示边的结构体(终点,容量,费用反向边)
struct edge
{
int to,cap,cost,rev;
};
int V;//顶点数
vector<edge> G[MAX_V];//图的邻接表表示
int dist[MAX_V];//最短距离
int prevv[MAX_V],preve[MAX_V];//最短路中的前驱结点和对应的边
//向图中增加一条从from到to容量为cap费用为cost的边
void add_edge(int from,int to,int cap,int cost)
{
G[from].push_back((edge){to,cap,cost,G[to].size()});
G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
//求解从s到t流量为f的最小费用流
//如果不能再增广则返回-1
int min_cost_flow(int s,int t,int f)
{
int res=0;
while(f>0){
//利用Bellman-Ford算法求解从s到t的最短路
fill(dist,dist+V,INF);
dist[s]=0;
bool update=true;
while(update){
update=false;
for(int v=0;v<V;v++){
if(dist[v]==INF) continue;
for(int i=0;i<G[v].size();i++){
edge &e=G[v][i];
if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
dist[e.to]=dist[v]+e.cost;
prevv[e.to]=v;
preve[e.to]=i;
update=true;
}
}
}
}
if(dist[t]==INF){
//不能再增广
return -1;
}
//沿s到t的最短路尽量增广
int d=f;
for(int v=t;v!=s;v=prevv[v]){
d=min(d,G[prevv[v]][preve[v]].cap);
}
f-=d;
res+=d*dist[t];
for(int v=t;v!=s;v=prevv[v]){
edge &e=G[prevv[v]][preve[v]];
e.cap-=d;
G[v][e.rev].cap+=d;
}
}
return res;
}
//模板
例题
http://poj.org/problem?id=2135/
2.代码2
时间复杂度为O(F|V|log|V|)或许是O(F|V|^2)
#define INF 0x7fffffff
//最小费用流模板
#define MAX_V 1005
typedef pair<int,int> P;//first保存最短距离,second保存顶点编号
//用于表示边的结构体(终点,容量,费用反向边)
struct edge
{
int to,cap,cost,rev;
};
int V;//顶点数
vector<edge> G[MAX_V];//图的邻接表表示
int h[MAX_V];//顶点的势
int dist[MAX_V];//最短距离
int prevv[MAX_V],preve[MAX_V];//最短路中的前驱结点和对应的边
//向图中增加一条从from到to容量为cap费用为cost的边
void add_edge(int from,int to,int cap,int cost)
{
G[from].push_back((edge){to,cap,cost,G[to].size()});
G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
//求解从s到t流量为f的最小费用流
//如果不能再增广则返回-1
int min_cost_flow(int s,int t,int f)
{
int res=0;
fill(h,h+V,0);//初始化h
while(f>0){
//使用Dijkstra算法更新h
priority_queue<P,vector<P>,greater<P> > que;
fill(dist,dist+V,INF);
dist[s]=0;
que.push(P(0,s));
while(!que.empty()){
P p=que.top();
que.pop();
int v=p.second;
if(dist[v]<p.first) continue;
for(int i=0;i<G[v].size();i++){
edge &e=G[v][i];
if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
prevv[e.to]=v;
preve[e.to]=i;
que.push(P(dist[e.to],e.to));
}
}
}
if(dist[t]==INF){
//不能再增广
return -1;
}
for(int v=0;v<V;v++){
h[v]+=dist[v];
}
//沿s到t的最短路尽量增广
int d=f;
for(int v=t;v!=s;v=prevv[v]){
d=min(d,G[prevv[v]][preve[v]].cap);
}
f-=d;
res+=d*h[t];
for(int v=t;v!=s;v=prevv[v]){
edge &e=G[prevv[v]][preve[v]];
e.cap-=d;
G[v][e.rev].cap+=d;
}
}
return res;
}
//模板