最大流(SAP)及最小费用最大流(SPFA)模版
来源:互联网 发布:守望先锋怎么看数据 编辑:程序博客网 时间:2024/06/06 05:28
最大流SAP算法模板dfs
//SAP算法#include<stdio.h>#include<string.h>#include<algorithm>#define inf 9999999#define M 1007#define MIN(a,b) a>b?b:a;using namespace std;struct E{ int v,w,next;}edg[500000];int dis[2000],gap[2000],head[2000],nodes;int sourse,sink,nn;void addedge(int u,int v,int w){ edg[nodes].v=v; edg[nodes].w=w; edg[nodes].next=head[u]; head[u]=nodes++; edg[nodes].v=u; edg[nodes].w=0;//或者w edg[nodes].next=head[v]; head[v]=nodes++;}int dfs(int src,int aug){ if(src==sink)return aug; int left=aug,mindis=nn; for(int j=head[src];j!=-1;j=edg[j].next) { int v=edg[j].v; if(edg[j].w) { if(dis[v]+1==dis[src]) { int minn=MIN(left,edg[j].w); minn=dfs(v,minn); edg[j].w-=minn; edg[j^1].w+=minn; left-=minn; if(dis[sourse]>=nn)return aug-left; if(left==0)break; } if(dis[v]<mindis) mindis=dis[v]; } } if(left==aug) { if(!(--gap[dis[src]]))dis[sourse]=nn; dis[src]=mindis+1; gap[dis[src]]++; } return aug-left;}int sap(int s,int e){ int ans=0;nn=e+1; memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); gap[0]=nn; sourse=s; sink=e; while(dis[sourse]<nn) ans+=dfs(sourse,inf); return ans;}int main(){ int t; scanf("%d",&t); while(t--) { int n,s=0,sum=0; memset(head,-1,sizeof(head)); nodes=0; 建图 int anss=sap(s,t); printf("%d\n",anss); } return 0;}
sap算法bfs版
#include<stdio.h>#include<string.h>#include<algorithm>#define MAXN 20010 //点#define MAXM 880010//边#define inf 0x3f3f3fusing namespace std;struct E{ int from,v,next; int cap;} edge[MAXM];int num;int head[MAXN],dis[MAXN],gap[MAXN];int nn;//代表点的个数void init(){ num=0; memset(head,-1,sizeof(head));}void addedge(int u,int v,int w){ edge[num].from=u;edge[num].v=v;edge[num].cap=w; edge[num].next=head[u];head[u]=num++; edge[num].from=v;edge[num].v=u;edge[num].cap=0; edge[num].next=head[v];head[v]=num++;}void BFS(int start,int end){ memset(dis,-1,sizeof(dis)); memset(gap,0,sizeof(gap)); gap[0]=1; int que[MAXN]; int front,rear; front=rear=0; dis[end]=0; que[rear++]=end; while(front!=rear) { int u=que[front++]; if(front==MAXN)front=0; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(dis[v]!=-1)continue; que[rear++]=v; if(rear==MAXN)rear=0; dis[v]=dis[u]+1; ++gap[dis[v]]; } }}int SAP(int start,int end){ int res=0; nn=end+1; BFS(start,end); int cur[MAXN]; int S[MAXN]; int vp=0; memcpy(cur,head,sizeof(head)); int u=start; int i; while(dis[start]<nn) { if(u==end) { int temp=inf; int inser; for(i=0; i<vp; i++) if(temp>edge[S[i]].cap) { temp=edge[S[i]].cap; inser=i; } for(i=0; i<vp; i++) { edge[S[i]].cap-=temp; edge[S[i]^1].cap+=temp; } res+=temp; vp=inser; u=edge[S[vp]].from; } if(u!=end&&gap[dis[u]-1]==0) break; for(i=cur[u]; i!=-1; i=edge[i].next) if(edge[i].cap!=0&&dis[u]==dis[edge[i].v]+1) break; if(i!=-1) { cur[u]=i; S[vp++]=i; u=edge[i].v; } else { int min=nn; for(i=head[u]; i!=-1; i=edge[i].next) { if(edge[i].cap==0)continue; if(min>dis[edge[i].v]) { min=dis[edge[i].v]; cur[u]=i; } } --gap[dis[u]]; dis[u]=min+1; ++gap[dis[u]]; if(u!=start)u=edge[S[--vp]].from; } } return res;}int main(){ int s,t,n,m; scanf("%d%d",&n,&m); init(); s=0; t=n+1; int ans=SAP(s,t); printf("%d\n",ans); return 0;}
最小费用最大流 模版
一、最小费用最大流的模型
在保证流量最大的前提下,所需的费用最小,这就是最小费用最大流问题.
带有费用的网络流图: G=(V,E,C,W)
V:顶点; E:弧;C:弧的容量;W:单位流量费用。
任意的弧<i,j>对应非负的容量c[i,j]和单位流量费用w[i,j]。满足:
① 流量f是G的最大流。
② 在f是G的最大流的前提下,流的费用最小。
F是G的最大流的集合(最大流不止一个):
在最大流中寻找一个费用最小的流 f.
二、最小费用最大流的算法
基本思路:
把弧<i,j>的单位费用w[i,j]看作弧<i,j>的路径长度,每次找从源点s到汇点t长度最短(费用最小)的可增广路径进行增广。
1. 最小费用可增广路
2. 路径s到t的长度即单位流量的费用。
ps:是网络流EK算法的改进,在求增广路径的时候,把bfs改为带权的spfa,每次求权值最小的增广路。
ps:要注意一点,逆边cost[i][j] = -cost[j][i],不能忘了加上去。
自己的模板:邻接矩阵。#include<iostream>using namespace std; int n, ans;int cap[Max][Max], pre[Max];int cost[Max][Max], dis[Max];int que[Max];bool vis[Max]; bool spfa(){ // 源点为0,汇点为n。 int i, head = 0, tail = 1; for(i = 0; i <= n; i ++){ dis[i] = inf; vis[i] = false; } dis[0] = 0;// dis 表示 最小 花费 que[0] = 0; vis[u] = true; while(tail != head){ // 循环队列。 int u = que[head]; for(i = 0; i <= n; i ++) if(cap[u][i] && dis[i] > dis[u] + cost[u][i]){ // 存在路径,且权值变小。 dis[i] = dis[u] + cost[u][i]; pre[i] = u; if(!vis[i]){ vis[i] = true; que[tail ++] = i; if(tail == Max) tail = 0; } } vis[u] = false; head ++; if(head == Max) head = 0; } if(dis[n] == inf) return false; return true;} void end(){ int i, sum = inf; for(i = n; i != 0; i = pre[i]) sum = min(sum, cap[pre[i]][i]); for(i = n; i != 0; i = pre[i]){ cap[pre[i]][i] -= sum; cap[i][pre[i]] += sum; ans += cost[pre[i]][i] * sum; // cost[][]记录的为单位流量费用,必须得乘以流量。 }} int main(){ .... ans = 0; while(spfa()) end(); .... return 0;}
不MLE的最小费用最大流模板:
#include<iostream>#include<algorithm>#include<cstring>#include<queue>#include<cstdio>using namespace std;const int MAXN=610*610*2+2;const int inf=1<<29;int pre[MAXN]; // pre[v] = k:在增广路上,到达点v的边的编号为kint dis[MAXN]; // dis[u] = d:从起点s到点u的路径长为dint vis[MAXN]; // inq[u]:点u是否在队列中int path[MAXN];int head[MAXN];int NE,tot,ans,max_flow,map[666][666];struct node{ int u,v,cap,cost,next;} Edge[MAXN<<2];void addEdge(int u,int v,int cap,int cost){ Edge[NE].u=u; Edge[NE].v=v; Edge[NE].cap=cap; Edge[NE].cost=cost; Edge[NE].next=head[u]; head[u]=NE++; Edge[NE].v=u; Edge[NE].u=v; Edge[NE].cap=0; Edge[NE].cost=-cost; Edge[NE].next=head[v]; head[v]=NE++;}int SPFA(int s,int t) // 源点为0,汇点为sink。{ int i; for(i=s;i<=t;i++) dis[i]=inf; memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); dis[s] = 0; queue<int>q; q.push(s); vis[s] =1; while(!q.empty()) // 这里最好用队列,有广搜的意思,堆栈像深搜。 { int u =q.front(); q.pop(); for(i=head[u]; i!=-1;i=Edge[i].next) { int v=Edge[i].v; if(Edge[i].cap >0&& dis[v]>dis[u]+Edge[i].cost) { dis[v] = dis[u] + Edge[i].cost; pre[v] = u; path[v]=i; if(!vis[v]) { vis[v] =1; q.push(v); } } } vis[u] =0; } if(pre[t]==-1) return 0; return 1;}void end(int s,int t){ int u, sum = inf; for(u=t; u!=s; u=pre[u]) { sum = min(sum,Edge[path[u]].cap); } max_flow+=sum; //记录最大流 for(u = t; u != s; u=pre[u]) { Edge[path[u]].cap -= sum; Edge[path[u]^1].cap += sum; ans += sum*Edge[path[u]].cost; // cost记录的为单位流量费用,必须得乘以流量。 }}int main(){ int i,j,n,s,t; while(scanf("%d",&n)!=EOF) { memset(head,-1,sizeof(head)); NE=ans=max_flow=s=0; while(SPFA(s,t)) { end(s,t); } printf("%d\n",ans); } return 0;}
spfa算法来求最短路径:
#include<algorithm>#include<cstring>#include<queue>#include<cstdio>#define MAXN 1000007#define inf 0x3f3f3f3fusing namespace std;long long dis[MAXN]; // dis[u] = d:从起点s到点u的路径长为dint vis[MAXN]; // inq[u]:点u是否在队列中int head[MAXN];int NE,n,m;//n是点的数量,m是边的数量int a[MAXN],b[MAXN],c[MAXN];struct node{ int v,cap,next;} Edge[MAXN<<2];void addEdge(int u,int v,int cap){ Edge[NE].v=v; Edge[NE].cap=cap; Edge[NE].next=head[u]; head[u]=NE++;}void init(){ NE=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); for(int i=0;i<=n;i++) dis[i]=inf;}long long SPFA(int s) // 源点为0,汇点为sink。{ long long count=0; queue<int>q; q.push(s); dis[s] = 0; vis[s] =1; while(!q.empty()) // 这里最好用队列,有广搜的意思,堆栈像深搜。 { int u =q.front(); q.pop();vis[u]=0; for(int i=head[u]; i!=-1;i=Edge[i].next) { int v=Edge[i].v; if(dis[v]>dis[u]+Edge[i].cap) { dis[v]=dis[u]+Edge[i].cap; if(!vis[v]) { q.push(v); vis[v]=true; } } } } for(int i=1;i<=n;i++)//s到各个点最短路径之和 count+=dis[i]; return count;}int main(){ int cas; scanf("%d",&cas); while(cas--) { long long ans=0; scanf("%d%d",&n,&m); init(); for(int i=0;i<m;i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); addEdge(a[i],b[i],c[i]); } ans+=SPFA(1); printf("%lld\n",ans); } return 0;}
- 最大流(SAP)及最小费用最大流(SPFA)模版
- 最小费用最大流,SPFA
- 最小费用最大流模版
- 最小费用最大流模版
- 最小费用最大流模版
- 最小费用最大流模版(LRJ)
- poj2516(最小费用最大流模版)
- 最大流 SAP模板+ 最小费用最大流SPFA模板 +spfa求最短路径
- 最小费用最大流uva10806+spfa
- Farm Tour-最小费用最大流/SPFA
- 最小费用最大流 spfa() + ek()
- poj2195 spfa 最小费用最大流
- 【模板】SPFA增广 最小费用最大流
- hdu1533(最小费用最大流spfa模板)
- 最小费用最大流---MCMF模版
- poj9125+2135 最小费用最大流<模版>
- POJ 2195:Going Home(SPFA最小费用最大流)
- 最小费用最大流算法(SPFA邻接矩阵)
- Java序列化和Hessian序列化的区别
- lightoj Basic Math 数论基础题 1414+1010+1020+1078+1116+1148+1179+1214+1275+1294+1297+1311+1323+1349+1354
- 02-什么是域名?什么是网址?
- response.sendRedirect方式的转向与RequestDispatcher的forward方法的比较
- POJ 1584 A Round Peg in a Ground Hole【计算几何=_=你值得一虐】
- 最大流(SAP)及最小费用最大流(SPFA)模版
- 系统集成项目管理之项目进度管理
- eclipse 开发环境搭建-查看java src 和 doc
- Zstack之uart中断方式数据发送
- 完美解决desktop图标换行问题
- 怎么使用Xmanager连接linux
- 《大般涅槃经》略释 净慧法师
- 找新朋友
- hdu 3746 Cyclic Nacklace(KMP)