标签:
前言:网络流具有各种性质及应用,小艾在这个专题中将记录下最大流、最小费用流及二分匹配图的思想,并对相关算法的正确性予以证明。
类型:最大流
题意:网络中的计算机s与计算机t通过其它若干计算机连接,两两计算机间有一条单向通信电缆并且有对应的1秒钟内所能传输的最大数据量。问当仅有计算机s向计算机t传输数据时,1秒内可传输的最大数据量。
分析:记每条通信电缆即边对应的最大数据传输量为c(e),实际传输量为f(e)且f(e)满足条件0 <= f(e) <= c(e)。乍一看,该问题可以通过搜索解决:只要将s到t的所有可达路径找到,并选择一条最小边c(e)比其它路径的最小边都要大的路径进行本次数据传输f = c(e),然后修改该路径的相关数据即c(e‘)-f。重复上述操作直至不再有s到t的可达路径,那么便得到s到t的最大传输量。但是,分析可知,该算法效率低并且实现起来复杂,所以不建议采用。让我们再试试贪心算法:寻找任意一条满足f(e) < c(e)的可达路径,如果不存在满足条件的路径则算法结束,否则沿着该路径尽可能的增加c(e)直至算法结束。但这种贪心得到的答案是不正确的。我们可以对这样的贪心算法加以改进,即允许流回退。改进后的贪心算法如下:只利用满足f(e)<c(e)的边或者f(e)>0的边对应的反向边寻找一条s到t的路径,如果不存在满足条件的路径则结束,否则沿着该路径尽可能的增加流直至算法结束。改进后的贪心算法可以用于求解最大流,该思想的具体的实现可采用Ford_Fulkerson算法或Dinic算法,对应的时间复杂度为O(FE),O(VE)。
最大流算法的相关证明即最小割定理:
(1)割的概念:图的割(S, V\S)指从点集S出发指向S外部的边的集合,割的容量即这些边的容量之和。如果有s属于S,t属于V\S,此时的割又称为s-t的割。性质:如果将网络中s-t割所包含的边都删除,也就不再有s-t的可达路径,特别地满足这样条件的割中容量最小的称之为最小割。
(2)割与最大流的联系:设任意s-t的流f和任意的s-t的割(S, V\S)。f的流量=s出边的总流量, 对任意v属于S且v!=s恒有v的出边总流量=v的入边总流量,则f=S的出边总流量-S的入边总流量=割的容量-S的入边总流量。则f<=割的容量恒成立等价于f<=网络中的最小割。
(3)让我们考虑通过最大流算法所求得的f‘。记流f‘对应的残余网络中从s可达的顶点v组成的集合为S,由于f‘对应的残余网络中不存在s-t的可达路径,故(S, V\S)是一个s-t的割。则割(S, V\S)中的边e有f‘(e)=c(e),而从V\S到S的边e应该有f‘(e)=0(因反向边容量为c(e))。由此可得f‘=S出边的总流量=割(S, V\S)的容量并且该割为此网络的最小割。
代码实现://Ford_Fulkerson算法
#incldue<iostream>
#incldue<vector>
using namespace std;
struct edge
{//图的存储:邻接表
int t, c, r;
edge(int t1 = 0, int c1 = 0, int r1 = 0){t = t1, c = c1, r = r1;}
};
vector<edge> G[MAX_V];
bool used[MAX_V];
void add_edge(int s, int t, int c)
{//建图边的添加
G[s].push_back(edge(t, c, G[t].size()));
G[t].push_back(edge(s, 0, G[s].size() - 1));
}
int dfs(int v, int t, int f)
{//通过深搜寻找增广路
if(v == t)
return f;
used[v] = 1;
int sz = G[v].size();
for(int i = 0; i < sz; ++i)
{
edge &es = G[v][i];
if(es.c > 0 && !used[es.t])
{
int d = dfs(es.t, t, min(es.c, f));
if(d > 0)
{
es.c -= d;
G[es.t][es.r].c += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t, int n, int v)
{
int ans = 0;
while(1)
{
memset(used, 0, sizeof(used));
int f = dfs(s, t, INF);
if(f == 0)
return ans;
ans += f;
}
}
void solve(int s, int t, int v, int n)//源点 汇点 顶点数 边数
{
for(i = 0; i < n; ++i)
{//建图
int s1, t1, c1;
cin >> s1 >> t1 >> c1;
add_edge(s1, t1, c1);
}
cout << max_flow(s, t, n, v) << endl;
}
int main()
{
int v, n, s, t;
cin >> v >> n >> s >> t;
solve(s, t, v, n);
return 0;
}
标签:
原文地址:http://www.cnblogs.com/aizi/p/4671794.html