网络流最大流算法(ISAP算法及DINIC算法)
来源:互联网 发布:奥尔弗斯 知乎 编辑:程序博客网 时间:2024/06/06 04:58
这些算法网络中解释都有,所有以下是根据题目应用,代码中有注释,方便理解,ISAP算法就是通过先bfs一遍建立逆序求层数,然后每次都进行维护求最短路来求增广路径,下次查找建立在上次查找的最小路径的源点进行继续查找,DINIC即是通过顺序,每次找最短路径前都进行一次层次的划分(相当于先找出这次查找可能的最小路径长度),再来求最短路增广路径,直至无法划分层次出现断层。下面用两个方法来做这道题,可以作为模板使用
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=4280
题意:有N个岛屿,M条路线,每条路线连接两个岛屿,并且每条路有最大客流量,这是无向的,就是可以过去也可以回来,现在求最西边到最东边的岛屿,最多有多少人可以过去,每次保证最东边和最西边岛屿只有一个。显示输入N行x,y左边,后面接着路线和客流量
题解:裸算法,直接求即可,ISAP比较好,时间快
代码:
ISAP算法
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<queue>#define DIAN_MAX 435050#define BIAN_MAX 435050#define INF 0xfffffffusing namespace std;typedef struct{ int from,tail,cost,next;}Edge;int n,m;//n为点的数量,m为边的数量Edge edge[BIAN_MAX]; //邻接表存储边int ecount; //存储边的当前位置int head[DIAN_MAX]; //点头数组int copyhead[DIAN_MAX];//head的复制版int layer[DIAN_MAX]; //层次数组int gap[DIAN_MAX]; //gap,用于优化该算法,只要出现断层,就说明该算法可以结束了int myqueue[DIAN_MAX]; //自定义的队列int start,tail; //开始点和终止点int edgestack[DIAN_MAX]; //自定义栈,用于存放一条起始点到终点的最短路路径void addEdge(int s,int e,int cost)//针对无向和有向皆可{ edge[ecount].from=s; edge[ecount].tail=e; edge[ecount].cost=cost; edge[ecount].next=head[s]; head[s]=ecount++; //反向路径,用于后悔的情况 edge[ecount].from=e; edge[ecount].tail=s; edge[ecount].cost=0; edge[ecount].next=head[e]; head[e]=ecount++;}void bfs() //先进行bfs来分层,逆序来求层次,从最终点到起始点,最终点层次为0{ memset(gap,0,sizeof(gap)); memset(layer,-1,sizeof(layer)); int first=0,last=0,i,now,next; myqueue[last++]=tail; gap[0]=1; //表示第0层次存在1个点 同理推i layer[tail]=0; //表示第tail点层次为1 while(first<last) { now=myqueue[first++]; first=first%DIAN_MAX; for(i=head[now];i!=-1;i=edge[i].next) { next=edge[i].tail; //逆推层次 if(edge[i].cost!=0||layer[next]!=-1) continue; myqueue[last++]=next; last=last%DIAN_MAX; layer[next]=layer[now]+1; gap[layer[next]]++; } }}int ISAP(){ int ans=0; bfs(); memcpy(copyhead,head,sizeof(head)); int top=0,now=start,i,minn,op; while(layer[start]<n) { if(now==tail)//这种情况即表示已经找到了从开始点到终点的一条路径 { minn=INF; for(i=0;i<top;i++)//找出路径中的最小距离,用于更新其他路径 { if(minn>edge[edgestack[i]].cost) { minn=edge[edgestack[i]].cost; op=i; } } ans+=minn; //用最小路径更新 for(i=0;i<top;i++) { edge[edgestack[i]].cost-=minn; edge[edgestack[i]^1].cost+=minn; } //用最小路径的起始点来更新接下来要找的起始点, //因为减去的边是最小的,所以前面边一定没有剪成0,免去了从新遍历 top=op; now=edge[edgestack[top]].from; } //当出现断层时就直接结束,即从S无法到到T集合 if(now!=tail&&gap[layer[now]-1]==0) { break; } //找出层次差1即相邻,并且路径剩余量不为0的边 for(i=copyhead[now];i!=-1;i=edge[i].next) { if(edge[i].cost!=0&&layer[now]==layer[edge[i].tail]+1) break; } //若存在,就记录下点然后继续查找 if(i!=-1) { copyhead[now]=i; edgestack[top++]=i; now=edge[i].tail; } //若不存在,更新现在已经排除的路径,免得之后再找 else { //找出相邻的层次最小的点,该点可以到达此点,所以这点最小层次为找到的最小值+1 minn=n; for(i=head[now];i!=-1;i=edge[i].next) { if(edge[i].cost<=0) continue; if(minn>layer[edge[i].tail]) {minn=layer[edge[i].tail];copyhead[now]=i;} } //更新代数的数量 gap[layer[now]]--; layer[now]=minn+1; gap[minn+1]++; //从上一个点继续查找 if(now!=start) now=edge[edgestack[--top]].from; } } return ans;}int main(){ int t; scanf("%d",&t); while(t--) { memset(head,-1,sizeof(head)); ecount=0; scanf("%d %d",&n,&m); int minn=1000000; int maxx=-1000000; for(int i=1;i<=n;i++) { int x,y; scanf("%d %d",&x,&y); if(x<minn){minn=x;start=i;} else if(x>maxx){maxx=x;tail=i;} } for(int i=0;i<m;i++) { int s,d,w; scanf("%d %d %d",&s,&d,&w); addEdge(s,d,w); addEdge(d,s,w); } printf("%d\n",ISAP()); } return 0;}
DINIC算法
#include<iostream>#include<cstdio>#include<cstring>#include<string>#define BIAN_MAX 400050#define DIAN_MAX 100050#define INF 0xfffffffusing namespace std;int n,m;int start,tail;typedef struct{ int from,to,cost,next;}Edge;Edge edge[BIAN_MAX];int myqueue[BIAN_MAX];int ecount;int head[DIAN_MAX];int layer[DIAN_MAX];void init(){ memset(head,-1,sizeof(head)); ecount=0;}void addedge (int u, int v, int flow){ edge[ecount].to = v; edge[ecount].next = head[u]; edge[ecount].cost = flow; head[u] = ecount++; swap (u, v); edge[ecount].to = v; edge[ecount].next = head[u]; edge[ecount].cost = flow; head[u] = ecount++;}bool bfs()//每次更新代数,即是找到最小的从起始到终点的距离,每次从起始点开始{ memset(layer,0,sizeof(layer)); int first=0,last=0,i,next,now; layer[start] = 1; myqueue[last++]=start; while(first<last) { now=myqueue[first++]; if(now==tail) return 1;//若找到了最后一点,直接返回,说明已经找到 first=first%BIAN_MAX; for(i=head[now];i!=-1;i=edge[i].next) { next=edge[i].to; //每次保证该点没有查找过并且有距离余额 if(!layer[next]&&edge[i].cost>0) { layer[next]=layer[now]+1; if(next==tail) return 1; myqueue[last++]=next; last%=BIAN_MAX; } } } return 0;}//通过层次来查找最短的路径int dfs(int s,int limit){ if(s==tail) return limit; int cost=0; for(int i=head[s];i!=-1;i=edge[i].next) { int next=edge[i].to; if(layer[next]==layer[s]+1&&edge[i].cost>0) { int tmp=dfs(next,min(limit-cost,edge[i].cost)); edge[i].cost-=tmp; edge[i^1].cost+=tmp; cost+=tmp; if(cost==limit) break; } } //优化,当这点不能到任意一点时,排除其他点到这点 if(!cost) layer[s]=0; return cost;}int dinic(){ int ans=0; while(bfs()) { ans+=dfs(start,INF); } return ans;}int main(){ int t; scanf("%d",&t); while(t--) { init(); scanf("%d %d",&n,&m); int minn=1000000,maxx=-1000000; for(int i=1;i<=n;i++) { int x,y; scanf("%d %d",&x,&y); if(x<minn) {minn=x;start=i;} if(x>maxx) {maxx=x;tail=i;} } for(int i=1;i<=m;i++) { int s,e,w; scanf("%d %d %d",&s,&e,&w); addedge(s,e,w); } printf("%d\n",dinic()); } return 0;}
0 0
- 网络流最大流算法(ISAP算法及DINIC算法)
- 最大流算法,Dinic,ISAP
- 网络流模板:最大流ISAP算法和Dinic算法
- 网络流模板:最大流ISAP算法和Dinic算法
- : 最大流(Dinic算法 + ISAP算法)
- 网络流算法总汇(ek,dinic,isap)
- isap算法网络最大流
- POJ-3281 : 最大流(Dinic算法 + ISAP算法)
- 最大流Dinic算法讲解 && ISAP 算法解释
- 最大网络流Dinic算法
- 网络最大流 dinic算法
- 网络流之最大流 EK/Dinic/Isap算法 学习笔记
- 网络流 最大流 ISAP算法
- Dinic算法(网络流,最大流)
- 最大流ISAP算法模板
- 最大流ISAP算法模板
- 最大流算法之ISAP
- 最大流问题 ISAP 算法
- SpringMvc MultipartFile 多张图片文件上传
- jquery中的on方法失效问题(ipone 动态生成的元素无法点击 )
- blob与string类型的相互转换——把stringlexington的数据存进oracle的blob字段中
- Android开源项目
- Linux 下安装python软件包(pip、nose、virtualenv、distribute )
- 网络流最大流算法(ISAP算法及DINIC算法)
- PHP获得数组的交集与差集
- 坐标尺寸 大锅烩
- 为什么一般hashtable的桶数会取一个素数
- Client-Side Data Storage-O'Reilly 2016(读书笔记): 这本书内容太弱了
- 动态规划----Maximun Subarray
- 漫步微积分二十六——Sigma符号和一些特殊和
- android-sdk-linux/tools/android: java: not found
- nginx与php-fpm通信的两种方式