这一篇讲有更新,仅提供目录。
网络流的算法实现
网络流建图
简单建图(HDU - 1532为例)
#include"stdio.h"
#include"string.h"
#include"queue"
#include"stack"
#include"iostream"
#include"stdlib.h"
#define inf 99999999
#define M 50000
using namespace std;
struct st
{
int u, v, w, next;
}edge[M];
int t, head[M], cur[M], q[M], gap[M], dis[M];
void init()
{
t = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
edge[t].u = u;
edge[t].v = v;
edge[t].w = w;
edge[t].next = head[u];
head[u] = t++;
edge[t].u = v;
edge[t].v = u;
edge[t].w = 0;
edge[t].next = head[v];
head[v] = t++;
}
void bfs(int start, int endl)//建立到汇点的距离层次图存在dis[]数组中
{
int rear = 0, i, j;
memset(dis, -1, sizeof(dis));
memset(gap, 0, sizeof(gap));//gap[x]记录dis[i]=x出现了多少次
dis[endl] = 0;
gap[dis[endl]] = 1;
q[rear++] = endl;
for (i = 0; i<rear; i++)
{
for (j = head[q[i]]; j != -1; j = edge[j].next)
{
int v = edge[j].v;
if (dis[v] == -1)
{
++gap[dis[v] = dis[q[i]] + 1];
q[rear++] = v;
}
}
}
}
int SAP(int start, int endl, int n)
{
int ans = 0;
bfs(start, endl);
int cur[M];//代替head数组
memcpy(cur, head, sizeof(head));
int stack[M], top = 0;//建立手工栈
int u = start, i;
while (dis[start]<n)
{
if (u == endl)//当搜到终点时即找到从原点到汇点的增光路,正常处理即可
{
int mini = inf, tep;
for (i = 0; i<top; i++)
{
if (mini>edge[stack[i]].w)
{
mini = edge[stack[i]].w;
tep = i;
}
}
for (i = 0; i<top; i++)
{
edge[stack[i]].w -= mini;
edge[stack[i] ^ 1].w += mini;
}
ans += mini;
top = tep;
u = edge[stack[top]].u;//此时的u为变容量为0的u
}
if (dis[u] && gap[dis[u] - 1] == 0)//出现了断层,没有增广路
break;
for (i = cur[u]; i != -1; i = edge[i].next)//遍历与u相连的未遍历的节点
{
int v = edge[i].v;
if (dis[v] != -1)
{
if (edge[i].w&&dis[u] == dis[v] + 1)//层次关系找到允许路径
break;
}
}
if (i != -1)//找到允许弧
{
cur[u] = i;
stack[top++] = i;
u = edge[i].v;
}
else//无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1
{
int mini = n;
for (i = head[u]; i != -1; i = edge[i].next)
{
if (edge[i].w == 0)continue;
int v = edge[i].v;
if (mini>dis[v])//找到与u相连的v中dep[v]最小的点
{
mini = dis[v];
cur[u] = i;//最小标号就是最新的允许弧
}
}
--gap[dis[u]];//dep[u] 的个数变化了 所以修改gap
++gap[dis[u] = mini + 1];//将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]
if (u != start)//该点非源点&&以u开始的允许弧不存在,退点
u = edge[stack[--top]].u;
}
}
return ans;
}
int main()
{
int n, m;
while (scanf("%d%d", &m, &n) != -1)
{
init();
while (m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
int ans = SAP(1, n, n);
printf("%d\n", ans);
}
}
拓展建图
任务建图(HDU - 3572 为例)
INF建图(POJ—1149为例)
拆点建图(POJ-3281为例)
练习题(HDU - 2732题解)
未完,待续
再拓展: