首页 > 其他分享 >费用流

费用流

时间:2022-12-25 16:58:42浏览次数:55  
标签:费用 int 餐巾 vis ans dis

title: 费用流
tags: 算法
date: 2022-11-23 05:21:28

本文章遵守知识共享协议 CC-BY-NC-SA ,转载时须在文章的任一位置附上原文链接和作者署名(rickyxrc)。推荐在我的个人博客阅读。

简介

费用流是网络流的拓展,一般用于求解一些多次取点的问题。

前置知识

  • 网络流
  • 最短路

讲解

定义

在网络流中,在花费费用最小时的最大流。

如果有冲突,则优先满足最大流。

实现

大体逻辑和网络流区别不大,只是将算法中的 bfs 改为spfa或其他最短路算法,以费用为边权搜索最短路。

费用流算法可以基于 EKDinic 改来,下面这一版是基于 Dinic 更改而来的。

bool spfa(int s, int t) {
  memset(dis, 0x3f, sizeof(dis)); // 初始化距离数组
  memcpy(cur, lnk, sizeof(lnk)); // 复制数组状态
  queue<int> q;  // 正常的spfa
  q.push(s), dis[s] = 0, vis[s] = 1;
  while (!q.empty()) {
    int u = q.front();
    q.pop(), vis[u] = 0;
    for (int i = lnk[u]; i; i = nxt[i]) {
      int v = ter[i]; // 队首节点
      if (cap[i] && dis[v] > dis[u] + cost[i]) {
        dis[v] = dis[u] + cost[i]; // 注意这里是以费用为单位更新
        if (!vis[v]) q.push(v), vis[v] = 1;
      }
    }
  }
  return dis[t] != INF; // 代表是否可以到达汇点
}

int dfs(int u, int t, int flow) {
  if (u == t) return flow; // 搜索结束
  vis[u] = 1; // 标记已访问
  int ans = 0;
  for (int &i = cur[u]; i && ans < flow; i = nxt[i]) {
    int v = ter[i]; // 队首节点
    if (!vis[v] && cap[i] && dis[v] == dis[u] + cost[i]) {
      int x = dfs(v, t, min(cap[i], flow - ans)); // 
      if (x)
        ret += x * cost[i],  // 单位费用
        cap[i] -= x, // 正向边减流
        cap[i ^ 1] += x, ans += x; // 反向边增流
    }
  }
  vis[u] = 0; // 撤销标记状态,方便下一次
  return ans;
}

int solve(int s, int t) {
  int ans = 0;
  while (spfa(s, t)) {  // 这里进行了改动,将原先的bfs改成了spfa
    int x;
    while ((x = dfs(s, t, INF))) ans += x; // 一次dfs多次增流
  }
  return ans;
}

 // 最后费用为ret

例题

P1004-[NOIP2000-提高组]-方格取数

P2045 方格取数加强版

这道题的难点在于构建费用流网络,首先分析题目性质:

  • 一个格子只能取一次数字
  • 可以走多次

根据这些可以构建出第一个图:

在每个点的连接处连流量为 \(2\) ,费用为 \(-val_i\) 的边,然后跑最大流。

第一种思路

先别急着翻到下面去,这个构建方法显然是错误的,因为没有考虑到走的次数,并且一个点可能被统计多次。

所以便有了下面这种方法。

首先,我们需要拆S,T点并添加限流才能确保没问题。

还有一点就是像 1->1' 这里要连两条边,第一条容量 \(1\) 费用 \(0\) 确保联通,第二条容量 \(1\) 费用 \(-val_i\) 才是实际能取到的价值

最后构建出的图

最后的图就是这样。

其实不管是网络流,还是费用流,最难的部分都是构建图,需要多理解为什么这么构建才能过这道题,只要理解了,那这一类的题型都不是什么难事。

代码写的有点丑,见谅。

s = 0, t = 2*n*n + 1;
addedge(s, 1, k,0); // 源点连 (1,1)
addedge(2*n*n, t, k,0); // (n,n) 的出点连汇点
for(int i=1;i<=n*n;i++){ // 先输入
  scanf("%d",&val);
  addedge(i,i+n*n,1,-val); // 因为这个点只能取一次
  addedge(i,i+n*n,k-1,0); // 其他时候也需要联通
}
for(int i=1;i<=n*n;i++){ // 然后枚举每个点
  if((i - 1) / n + 1 != n)
    addedge(i+n*n,i+n,k,0); // 出点连下面的入点
  if((i - 1) % n + 1!=n)
    addedge(i+n*n,i+1,k,0); // 出点连左边的入点
}
printf("%d",dinic(s,t));

P1251 餐巾计划问题

这道题目的构建方法很新颖,单独提出来讲一下。

最大的问题是区分干净的餐巾和脏餐巾,这里可以将一天拆成早上和晚上。

首先要保证这里的流量,也就是每天早上的餐巾数量达标。

所以这里可以从每天早上向汇点连边,流量为当天需要的餐巾数量,费用为\(0\)。

还要从每天早上到每天晚上连边,容量为当天需要的餐巾数量,费用为\(0\)。

再根据题目的规则,很容易想到每天早上到下一天早上,每天晚上到下一天晚上连边,流量\(inf\),费用\(0\)(保留干净的餐巾和脏餐巾)。

然后考虑送洗,中间的变化是 脏餐巾 -> 干净餐巾,所以可以从每天晚上到 当前天数+快洗天数的早上 连一条边,流量\(inf\),费用为快洗费用,慢洗同理。

购买餐巾也很简单,就从源点往每天早上连边,流量\(inf\),费用为购买餐巾费用。

贴上核心代码:

int night(int i){return i+n;} // 每天晚上的编号
for (int i = 1; i <= n; i++)
{
  scanf("%d", &tmp); // 每天需求的餐巾数量
  addedge(i, t, tmp, 0); // 保证餐巾数量足够
  addedge(s, night(i), tmp, 0); // 使用完的餐巾变成脏餐巾
}
scanf("%d%d%d%d%d", &pp, &mm, &f, &nn, &ss);
for (int i = 1; i <= n; i++)
{
  addedge(s, i, INF, pp); // 购买餐巾
  if (i + 1 <= n)
  {
    addedge(i, i + 1, INF, 0); // 保留干净餐巾
    addedge(night(i), night(i + 1), INF, 0); // 保留脏餐巾
  }
  if (i + mm <= n)
    addedge(night(i), i + mm, INF, f); // 快洗
  if (i + nn <= n)
    addedge(night(i), i + nn, INF, ss); // 慢洗
}

标签:费用,int,餐巾,vis,ans,dis
From: https://www.cnblogs.com/rickyxrc/p/17004223.html

相关文章

  • 云渲染怎么收费的,哪个云渲染平台费用低?速看!
    Renderbus瑞云渲染小编小瑞今天来给大家分享一下云渲染怎么收费的?云渲染哪个平台费用低?这两个问题。云渲染是怎么收费的?市面上云渲染平台大部分都是按渲染时间进行收费......
  • 云渲染哪个平台费用低??云渲染收费答疑!
    Renderbus瑞云渲染小编小瑞今天来给大家分享一下云渲染怎么收费的?云渲染哪个平台费用低?这两个问题。云渲染是怎么收费的?市面上​​云渲染平台大部分都是按渲染时间进行收费......
  • RayLink 远控软件又推出 2 个重磅宝藏功能免费用
    你有没有在远程办公时,担心他人偷窥电脑?以致于保密性资料或私密信息,遭到泄露、创意被剽窃......又或是遇到过邻座同事屏幕前明明没人,鼠标箭头却自个浏览起网页的惊悚画面?如......
  • Google发外链费用预算要投入多少?谷歌seo收费组成
    对于项目方,谷歌发外链到底有投入多少钱才比较合适?答案是:项目总费用的20~30%现在市场上有很多做谷歌seo的代运营,无论他们有怎样的承诺,服务特色,还是独有的优势,都离不开几个大......
  • 做谷歌seo一个月费用需要2万吗
    答案是:不用目前市场价做谷歌seo代运营服务的,都是按年收费的,包月很少一般一年的价格都是5万~25万左右这个根据客户需求定制的,越贵服务就越多,效果就越好一个月2万就有点夸张了......
  • 牛客挑战赛65 E 费用流
    233的物品出题人钟爱阴间费用流。看起来很不可做也像是费用流的模型。也有匹配味道。考虑一个点既在S集合又在T集合相当难以处理。但是注意到一个点在S集合就一定要有......
  • 5、Excel—在做车辆费用汇总的时候,复制出来的数据跟同事的一样,但是合计总数就不一样
    在做车辆费用汇总的时候,复制出来的数据跟同事的一样,但是合计总数就不一样,刚开始以为是数值问题,明明两份Excel都是同样的数据,为什么合计就不一样呢?(根据同事那份的数据,然后......
  • 2022牛客多3 B 模拟费用流
    B题目很短,出的最小费用最大流。好像付费报名才能看。当然不是裸题,是我也不会写,好久没写网络流了。因为将图建出来边数为1e6每次增广也是增广1流量复杂度显然不能接受......
  • 北京网络安全培训的费用是多少?学习周期多久?
    众所周知,网络安全是当下非常热门的行业,与其他行业相比其薪资、前景、需求量都具有一定的优势,也正因这些吸引了大批人的目光,无论是刚刚毕业的大学生、还是其他IT从业者,甚......
  • 买卖1万元需要缴纳多少的费用?
     买卖1万元需要缴纳多少的费用?其实这些费用就是我们买卖股票的成本,非常好算。买卖股票的成本费用可以分为买入股票的成本费用和卖出股票的成本费用,一进一出的费用加起来......