码迷,mamicode.com
首页 > 其他好文 > 详细

最大流

时间:2015-07-23 23:12:45      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:

前言:网络流具有各种性质及应用,小艾在这个专题中将记录下最大流、最小费用流及二分匹配图的思想,并对相关算法的正确性予以证明。

类型:最大流

题意:网络中的计算机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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!