网络流模板

来源:互联网 发布:自己编曲的软件 编辑:程序博客网 时间:2024/05/17 07:58



Edmond Karp 算法:


#include <iostream>#include <queue>#include<string.h>using namespace std;#define arraysize 201int maxData = 0x7fffffff;int capacity[arraysize][arraysize]; //记录残留网络的容量int flow[arraysize];                //标记从源点到当前节点实际还剩多少流量可用int pre[arraysize];                 //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中int n,m;queue<int> myqueue;int BFS(int src,int des){    int i,j;    while(!myqueue.empty())       //队列清空        myqueue.pop();    for(i=1;i<m+1;++i)    {        pre[i]=-1;    }    pre[src]=0;    flow[src]= maxData;    myqueue.push(src);    while(!myqueue.empty())    {        int index = myqueue.front();        myqueue.pop();        if(index == des)            //找到了增广路径            break;        for(i=1;i<m+1;++i)        {            if(i!=src && capacity[index][i]>0 && pre[i]==-1)            {                 pre[i] = index; //记录前驱                 flow[i] = min(capacity[index][i],flow[index]);   //关键:迭代的找到增量                 myqueue.push(i);            }        }    }    if(pre[des]==-1)      //残留图中不再存在增广路径        return -1;    else        return flow[des];}int EK(int src,int des){    int increasement= 0;    int sumflow = 0;    while((increasement=BFS(src,des))!=-1)    {         int k = des;          //利用前驱寻找路径         while(k!=src)         {              int last = pre[k];              capacity[last][k] -= increasement; //改变正向边的容量              capacity[k][last] += increasement; //改变反向边的容量              k = last;         }         sumflow += increasement;    }    return sumflow;}int main(){    int i,j;    int start,end,ci;    while(cin>>n>>m)    {        memset(capacity,0,sizeof(capacity));        memset(flow,0,sizeof(flow));        for(i=0;i<n;++i)        {            cin>>start>>end>>ci;            if(start == end)               //考虑起点终点相同的情况               continue;            capacity[start][end] +=ci;     //此处注意可能出现多条同一起点终点的情况(重边)        }        cout<<EK(1,m)<<endl;    }    return 0;}





Dinic非递归版:


#define N 5000#define M 1505#define inf 536870912//N为点数 M为边数struct Edge{int from, to, cap, nex;}edge[M*10];//注意这个一定要够大 不然会re 还有反向弧int head[N], edgenum;void addedge(int u, int v, int cap){Edge E = { u, v, cap, head[u]};edge[ edgenum ] = E;head[u] = edgenum ++;Edge E2= { v, u, 0,   head[v]};edge[ edgenum ] = E2;head[v] = edgenum ++;}int sign[N], s, t;bool BFS(int from, int to){memset(sign, -1, sizeof(sign));sign[from] = 0;queue<int>q;q.push(from);while( !q.empty() ){int u = q.front(); q.pop();for(int i = head[u]; i!=-1; i = edge[i].nex){int v = edge[i].to;if(sign[v]==-1 && edge[i].cap){sign[v] = sign[u] + 1, q.push(v);if(sign[to] != -1)return true;}}}return false;}int Stack[M*4], top, cur[M*4];int dinic(){int ans = 0;while( BFS(s, t) ){memcpy(cur, head, sizeof(head));int u = s;top = 0;while(1){if(u == t){int flow = inf, loc;//loc 表示 Stack 中 cap 最小的边for(int i = 0; i < top; i++)if(flow > edge[ Stack[i] ].cap){flow = edge[Stack[i]].cap;loc = i;}for(int i = 0; i < top; i++){edge[ Stack[i] ].cap -= flow;edge[Stack[i]^1].cap += flow;}ans += flow;top = loc;u = edge[Stack[top]].from;}for(int i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;if(cur[u] != -1){Stack[top++] = cur[u];u = edge[ cur[u] ].to;}else{if( top == 0 )break;sign[u] = -1;u = edge[ Stack[--top] ].from;}}}return ans;}


 


 

 

Dinic 递归版:

 


#define inf 1000000#define N 1000 #define M 100000//N为点数 M为边数inline int Min(int a,int b){return a>b?b:a;} //注意这个类型是intstruct Edge{int from, to, cap, nex;}edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重int head[N],edgenum;//2个要初始化-1和0void addedge(int u, int v, int cap){//网络流要加反向弧,即u->v 为10 则 v->u为 -10Edge E = {u, v, cap, head[u]};edge[ edgenum ] = E;head[ u ] = edgenum++;Edge E2 = {v, u, 0,  head[v]}; //这里的cap若是单向边要为0edge[ edgenum ] = E2;head[ v ] = edgenum++;}int dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为headbool vis[N];bool BFS(int Start,int End){//跑一遍最短路memset(vis,0,sizeof(vis)); memset(dis,-1,sizeof(dis));queue<int>Q;Q.push(Start);dis[Start]=0;vis[Start]=1;while(!Q.empty()){int u = Q.front(); Q.pop();for(int i = head[u]; i != -1; i = edge[i].nex){Edge E = edge[i];if( !vis[E.to] && E.cap > 0){vis[ E.to ] = true;dis[ E.to ] = dis[ u ] + 1;if(E.to == End) return true;Q.push( E.to );}}}return false;}int DFS(int x, int a,int End){//当前 流入x 的流量是a   流量a 是所有流过边中 边权的最小值if( x == End || a == 0)return a; int flow = 0, f; //flow表示从x点流到下面所有点,最大的流量for(int& i = cur[x]; i != -1; i = edge[i].nex){Edge& E = edge[i];if(dis[x] + 1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap), End))>0 ){E.cap -= f;edge[ i^1 ].cap += f;//反向边要减掉flow += f;a -= f;if(a==0)break;}}return flow;}int Maxflow(int Start,int End){int flow=0; while(BFS(Start,End)){ //当存在源点到汇点的路径时memcpy(cur,head,sizeof(head));//把head的数组复制过去flow += DFS(Start, inf, End);}return flow;}


ISAP 版:



typedef  struct {int v, next, val;} edge;const int MAXN = 20010;const int MAXM = 500010; edge e[MAXM];int p[MAXN], eid; inline void init() {memset(p, -1, sizeof(p));eid = 0;} //有向inline void insert1(int from, int to, int val) {e[eid].v = to;e[eid].val = val;e[eid].next = p[from];p[from] = eid++; swap(from, to); e[eid].v = to;e[eid].val = 0;e[eid].next = p[from];p[from] = eid++;} //无向inline void insert2(int from, int to, int val) {e[eid].v = to;e[eid].val = val;e[eid].next = p[from];p[from] = eid++; swap(from, to); e[eid].v = to;e[eid].val = val;e[eid].next = p[from];p[from] = eid++;} int n, m; //n为点数 m为边数int h[MAXN];int gap[MAXN]; int source, sink;inline int dfs(int pos, int cost) {if (pos == sink) {return cost;} int j, minh = n - 1, lv = cost, d; for (j = p[pos]; j != -1; j = e[j].next) {int v = e[j].v, val = e[j].val; if(val > 0) {if (h[v] + 1 == h[pos]) {if (lv < e[j].val) {d = lv;} else {d = e[j].val;} d = dfs(v, d);e[j].val -= d;e[j ^ 1].val += d;lv -= d; if (h[source] >= n) {return cost - lv;} if (lv == 0) {break;}} if (h[v] < minh){minh = h[v];}}} if (lv == cost) {--gap[h[pos]]; if (gap[h[pos]] == 0) {h[source] = n;} h[pos] = minh + 1;++gap[h[pos]];} return cost - lv; } int sap(int st, int ed) { source = st;sink = ed;int ret = 0;memset(gap, 0, sizeof(gap));memset(h, 0, sizeof(h)); //gap[st] = n;gap[0] = n; while (h[st] < n) {ret += dfs(st, INT_MAX);} return ret;}


0 0