●小集训之旅 三

2017.3.31

学习内容:网络流之求解最大流算法

引:最大流问题(maximum flow problem),一种组合最优化问题,就是要讨论如何充分利用装置的能力,使得运输的流量最大,以取得最好的效果。

●算法(e,我学了的……)

  • 枚举算法:
    • 由最小切割=最大流定理而来的暴力求法:
    • 枚举所有割来求最小割:
    • 代码图:
    • (资料上的东西,提供一种思路,正确性未知。)
  • 增广路算法:
  • 深度优先搜索(最大流 Ford-Fulkerson方法DFS实现):
    • 不断从源点开始深搜增广路,直到没有了增广路为止。
    • 特点:一旦搜索到一条增广路(能到达汇点且该路径的流量大于一)就回溯。
    • 代码:
    • int dfs(int x,int low)
      {
          if(x==m) return low;
          if(vis[x]) return 0;
          vis[x]=1;
          for(int flow,i=1;i<=m;i++)
          {
              if(tub[x][i]&&(flow=dfs(i,min(low,tub[x][i]))))
              {
                  tub[x][i]-=flow;
                  tub[i][x]+=flow;
                  return flow;
              }
          }
          return 0;
      }
      int maxflow(int s,int t)
      {
          int ans=0,flow;
          while(flow=dfs(1,INF)){memset(vis,0,sizeof(vis));;ans+=flow;}
          return ans;
      }
    • 注意到每一大次dfs中(即从maxflow()调用),对于点x来说,i都是从1开始枚举,浪费了不少时间。我们便可以用一个cur[ ]数组来优化一下:

      int dfs(int x,int low)
      {
          if(x==m) return low;
          if(vis[x]) return 0;
          vis[x]=1;
          for(int flow,i=cur[x];i<=m;i++)//枚举时从cur[x]或cur[x]+1开始似乎都可以,因为疯狂的while()会直到没有增广路才停下来;
          {
              if(tub[x][i]&&(flow=dfs(i,min(low,tub[x][i]))))
              {
                  cur[x]=i;
                  tub[x][i]-=flow;
                  tub[i][x]+=flow;
                  return flow;
              }
          }
          return 0;
      }
      int maxflow(int s,int t)
      {
          int ans=0,flow;
          while(flow=dfs(1,INF))
          {memset(vis,0,sizeof(vis));memset(cur,0,sizeof(cur));ans+=flow;}
          return ans;
      }
    • 图示cur[ ]作用:
  • Dinic算法
  • 利用层次图进行的求最大流算法。
  • 先进行bfs搜索建立层次图(计算每个点的深度),再dfs找增广路(每个点只能由深度比其小1的点搜索而来;把每个点在当层次图下的所有的增广路找完)
  • 也可用cur[ ]优化
  • 代码(Dinic+邻接链表)
  • bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue<int>q; q.push(1); d[1]=1; vis[1]=1;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];~i;i=e[i].next)if(e[i].capo)
            {
                int v=e[i].to; if(vis[v]) continue;
                d[v]=d[u]+1; vis[v]=1; q.push(v);
            }
        }
        return vis[m];
    }
    int dfs(int u,int res)
    {
        if(u==m||!res) return res; int flowout=0,v,f;
        for(int &i=cur[u];~i;i=e[i].next)
        {
            v=e[i].to; if(d[v]!=d[u]+1) continue;
            f=dfs(v,min(e[i].capo,res));
            e[i].capo-=f; e[i^1].capo+=f;
            flowout+=f; res-=f; if(!res) break;
        }
        return flowout;
    }
    int maxflow()
    {
        while(bfs())
        {
            for(int i=1;i<=m;i++) cur[i]=head[i];
            ans+=dfs(1,INF);
        }
    }
  • 注意上面两种算法的dfs的不同(前者是找到一条就猥琐的return了,后者是把该层次图下该点所有的增广路找完后,再return)
时间: 2024-11-03 21:41:27

●小集训之旅 三的相关文章

微信小程序把玩(三十六)Storage API

原文:微信小程序把玩(三十六)Storage API 其实这个存储在新建Demo的时候就已经用到了就是存储就是那个logs日志,数据存储主要分为同步和异步 异步存储方法: 存数据 wx.setStorage(object) 相同key会覆盖,可写回调方法 获取方法: wx.getStorage(object) 清除方法: wx.clearStorage()里面可以写回调函数 成功,失败,完成 同步存储方法: 存数据 相同key会覆盖 wx.setStorageSync(key,data) 读数据

JavaScript中易犯的小错误-------常见错误三:内存泄露

国庆放假,今天开始继续!!!!!!!!!!! JavaScript中易犯的小错误-------常见错误三:内存泄露 内存泄露在js变成中几乎是一个无法避免的问题.如果不是特别细心的话,在最后的检查过程中,肯定会出现各种内存泄露问题.下面我们就来举例说明一下:var theThing = null;var replaceThing = function () {     var priorThing = theThing;     var unused = function () {       

Python小爬虫-自动下载三亿文库文档

新手学python,写了一个抓取网页后自动下载文档的脚本,和大家分享. 首先我们打开三亿文库下载栏目的网址,比如专业资料(IT/计算机/互联网)http://3y.uu456.com/bl-197?od=1&pn=0,可以观察到,链接中pn=后面的数字就是对应的页码,所以一会我们会用iurl = 'http://3y.uu456.com/bl-197?od=1&pn=',后面加上页码来抓取网页. 一般网页会用1,2,3...不过机智的三亿文库用0,25,50...来表示,所以我们在拼接ur

微信小程序把玩(三十四)Audio API

原文:微信小程序把玩(三十四)Audio API 没啥可值得太注意的地方 重要属性: 1. wx.getBackgroundAudioPlayerState(object) 获取播放状态 2.wx.playBackgroundAudio(object)播放音乐 3.wx.pauseBackgroundAudio()暂停音乐 4.wx.seekBackgroundAudio(object) 设置播放进度 5.wx.stopBackgroundAudio()停止播放音乐 三个监听器: wxml <b

微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API

原文:微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API 反正我是没有测通这两个API!!!!不知道用的方式不对还是其他的!!!先记录下回头再说... 主要方法: wx.uploadFile(OBJECT)上传 wx.downloadFile(OBJECT)下载 wxml <button type="primary" bindtap="listenerButtonDownLoadFile"

Ajax之旅(三)-- 异步更新

上篇博文中,已经为大家在理论上讲述了什么是XMLHttpRequest对象,它是Ajax实现异步更新的核心对象.下面,我们就通过一个实例,来了解XMLHTTPRequest对象的使用或者说异步更新的实现. 实例:判断用户代码是否重复        方案一:同步更新.原理如下图所示: 从上图中可以看到,当我们在浏览器用户代码输入框中输入"用户代码"后,只能等待服务器的响应,当服务器将结果反馈给浏览器后,我们才可以进行下一个操作,也就是继续输入"用户名称". 这就是同步

微信小程序把玩(三十八)获取设备信息 API

原文:微信小程序把玩(三十八)获取设备信息 API 获取设备信息这里分为四种, 主要属性: 网络信息wx.getNetWorkType, 系统信息wx.getSystemInfo, 重力感应数据wx.onAccelerometerChange, 罗盘数据wx.onCompassChange wxml <button type="primary" bindtap="getNetWorkType">获取网络类型</button> <butt

微信小程序把玩(三十九)navigation API

原文:微信小程序把玩(三十九)navigation API 演示效果也看到了小程序也就提供这几个处理导航控制.值得注意的是只能同时导航五个页面 主要属性: 导航条一些方法 wx.setNavigationBarTitle(object) 设置导航条的Title 导航标题可以通过三种方式设置,第一种是通过全局配置名字统一,第二种就是在page中新建个json文件配置它会覆盖全局配置的title,第三种就是通过API设置. wx.showNavigationBarLoading()设置在导航条上显示

小谷实战Jquery(三)--横向纵向菜单

每天一个实例看来速率有点低了,今天要多做一点.好了,这次实现的是一个简单的菜单,Web项目中常见的菜单有两种:纵向和横向.从纵向说起,看一下最初的代码. html代码实现最基本的菜单与子菜单 <span style="font-size:18px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD