自NOIP 2014结束之后将近一个星期没撸题了,现在开始搞省选,发个水水的裸网络流题解吧。
题目链接:http://poj.org/problem?id=1273
裸网络流,模板题。
1、Edmond_Karp算法
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <queue> #define MAXV 220 #define MAXE 220 #define INF 0x3f3f3f3f using namespace std; int n,m; int cap[MAXV][MAXV],flow[MAXV][MAXV]; //容量、流量 int a[MAXV]; int last[MAXV]; int EdmondsKarp(int s,int t) //EK算法求s到t的最大流 { int sum=0; queue<int>q; while(1) { while(!q.empty()) q.pop(); q.push(s); memset(a,0,sizeof(a)); a[s]=INF; while(!q.empty()) //找增广路 { int u=q.front(); q.pop(); for(int v=1;v<=m;v++) { if(!a[v]&&flow[u][v]<cap[u][v]) { last[v]=u; q.push(v); a[v]=min(a[u],cap[u][v]-flow[u][v]); } } } if(a[t]==0) //找不到增广路,则已经找到最大流 break; sum+=a[t]; //加上这次增广得到的流量 for(int i=t;i!=s;i=last[i]) //根据增广路的链表顺着更新 { flow[last[i]][i]+=a[t]; flow[i][last[i]]-=a[t]; } } return sum; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { memset(cap,0,sizeof(cap)); memset(flow,0,sizeof(flow)); for(int i=1;i<=n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); cap[u][v]+=w; } printf("%d\n",EdmondsKarp(1,m)); } return 0; }
2、Dinic算法快速求网络流
#include <iostream> #include <queue> #include <vector> #include <algorithm> #include <deque> #include <cstring> #define mem(array,num) memset(array,num,sizeof(array)) #define MAXE 300 #define INF 0x3f3f3f3f using namespace std; int G[MAXE][MAXE]; bool visit[MAXE]; int Layer[300]; //Layer[i]=点i所在层数 int n,m; bool CountLayer() //BFS对图进行分层 { int layer=0; deque<int>q; mem(Layer,-1); //初始化所有层数都为-1 Layer[1]=0; //点1层数为0 q.push_back(1); //点1入队 while(!q.empty()) { int now=q.front(); q.pop_front(); for(int j=1;j<=m;j++) { if(G[now][j]>0&&Layer[j]==-1) //now->j有剩余容量且j还没被访问过 { Layer[j]=Layer[now]+1; if(j==m) return true; //分层到达了汇点即可 else q.push_back(j); } } } return false; //到达不了汇点,返回false } int Dinic() { int i,s,maxFlow=0; deque<int>q; //栈,DFS用 while(CountLayer()) //只要能分层 { q.push_back(1); //源点入栈 mem(visit,0); visit[1]=true; while(!q.empty()) { int top=q.back(); if(top==m) //top是汇点 { int minC=INF; //在栈中找容量最小的边 int SminC; //容量最小的边的起点 for(int i=1;i<q.size();i++) { int vs=q[i-1]; int ve=q[i]; if(G[vs][ve]>0) { if(minC>G[vs][ve]) //更新最小容量边 { minC=G[vs][ve]; SminC=vs; } } } //增广,改图 maxFlow+=minC; for(int i=1;i<q.size();i++) { int vs=q[i-1]; int ve=q[i]; G[vs][ve]-=minC; //减少边容量 G[ve][vs]+=minC; //增加反向边 } while(!q.empty()&&q.back()!=SminC) //退栈直到SminC成为栈顶,这样方便DFS { visit[q.back()]=false; q.pop_back(); } } else //top不是汇点 { int i; for(i=1;i<=m;i++) { if(G[top][i]>0&&Layer[i]==Layer[top]+1&&!visit[i]) //只往下一层没有走过的节点走 { visit[i]=1; q.push_back(i); break; } } if(i>m) //找不到下一个点,则往回走 q.pop_back(); } } } return maxFlow; } int main() { while(cin>>n>>m) //n边m点 { mem(G,0); for(int i=0;i<n;i++) { int u,v,c; cin>>u>>v>>c; G[u][v]+=c; //防止被坑,两点间可能有多条边,容量累加 } cout<<Dinic()<<endl; } return 0; }
时间: 2024-10-01 00:29:05