题目链接

http://uoj.ac/contest/47/problem/455

题解

模拟费用流,一个非常神奇的东西。
本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞模型,洞有容量和额外权值。
这道题的Subtask 4,5,6,7分别对应着老鼠进洞的最基础模型、洞有额外权值、洞有容量、洞有容量和额外权值四个变形。
让我们从最简单的开始各个击破。

Subtask 4

注: 本部分配合WC2019课件里的代码图理解效果更佳。
数轴上有\(n\)只老鼠(坐标\(x_i\))和\(m\)个洞(坐标\(y_i\)),每个老鼠必须进一个洞,每个洞至多进一只老鼠,最小化距离和。
假设洞\(i\)匹配了老鼠\(j\), 则若\(y_i<x_j\)代价为\(x_j+(-y_i)\), 否则为\((-x_j)+y_i\),不妨拆成\(i,j\)两部分分别计算。
使用可撤销贪心的策略。
维护一个老鼠堆和一个洞堆,从左到右扫描。
若当前扫到一只老鼠\(i\),那么先随便匹配一个目前空闲的洞(不妨假设负无穷远处有无穷多个洞),从洞堆中取出一个元素\(j\)匹配,其代价为\(x_i+j\)
考虑当后面插入洞的时候允许老鼠反悔(像极了费用流的反向边)而匹配新的洞,那么如果一个老鼠反悔而匹配了右面的新洞\(k\), 那么代价的增量为\((y_k-x_i)-(x_i+j)=y_k+(-2x_i-j)\), 所以往老鼠堆中插入元素\(-2x_i-j\).
若当前扫到一个洞\(j\),考虑是否有老鼠要反悔,从老鼠堆中取出一个元素\(i\), 若反悔的代价\(y_j+i>0\)那么让这个老鼠堆中的老鼠反悔,同时往洞堆中加入元素\(-2y_j-i\),表示后面的老鼠再匹配这个洞的代价;否则只往洞堆中插入元素\(-y_j\).
时间复杂度\(O(n\log n)\).

Subtask 5

洞有额外权值\(w\),怎么办呢?
考虑这样和原来有什么区别: 原来只有老鼠会反悔(因为不会有舍近求远故意匹配较远洞的情况),但是现在可能出现了!
解决办法:让洞和洞匹配,洞也可以反悔。
插入洞\(i\)时,除了往洞堆中插入元素之外,往老鼠堆也插入元素,表示该洞反悔的代价。插入的元素是\(-y_i-w_i\), 相当于用新洞\(j\)替代该洞会少这么多的代价再加上\(y_j+w_j\).
坑:WC课件中那个“老鼠和洞同时反悔不优”目前没看明白。

Subtask 6

洞有容量。
有一个神仙做法,见WC课件或UOJ题解。
正常做法: 往堆里存一个pair, 记录价值和剩余容量。
每次增广会使一个往左走的老鼠改为往右走,因此复杂度正确。

Subtask 7

洞有容量,也有附加权值,显然Subtask 6的做法时间复杂度错误。
但是我们发现,如果两个老鼠\(i,j\)分别匹配洞\(k\)且\(x_i<x_j<y_k\), 那么这两种情况下往洞堆中丢的元素是一样的,都是\(-y_k-w_k\).
所以我们可以“批量加入、批量增广”,这样复杂度就得到了保证。
其实这个东西就已经非常像费用流增广的过程了。
费用流的一条重要性质是: 如果不是每次选全局最短路,而是按另一顺序对和源点相连的边必须连的点进行增广,那么也是正确的。

建议结合代码以获取更好理解。

代码

代码写出来发现和费用流神相似!

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<queue>
#include<algorithm>
#define llong long long
using namespace std;const int N = 1e5;
const llong INF = 1000000000000ll;
struct Node
{int w; llong c;Node() {}Node(int _w,llong _c) {w = _w,c = _c;}bool operator <(const Node &arg) const {return c>arg.c;}
};
struct Element
{llong x,w,c;
} a[N+3],b[N+3];
priority_queue<Node> mouse,hole;
int n,m;
llong ans;void insertmouse(int x)
{llong ret = INF;if(!hole.empty()){Node tmp = hole.top();ret = tmp.c+x;hole.pop(); if(tmp.w-1>0) {hole.push(Node(tmp.w-1,tmp.c));}}ans += ret;mouse.push(Node(1,-x-ret));
}void inserthole(int x,int w,llong c)
{int rst = w;while(!mouse.empty() && rst>0){Node tmp = mouse.top();llong val = x+c+tmp.c;if(val>=0) break;int flow = min(rst,tmp.w);ans += val*flow; rst -= flow;hole.push(Node(flow,-val-x+c));mouse.pop(); if(tmp.w-flow>0) {mouse.push(Node(tmp.w-flow,tmp.c));}}if(rst>0) {hole.push(Node(rst,-x+c));}if(w-rst>0) {mouse.push(Node(w-rst,-x-c));}
}int main()
{scanf("%d%d",&n,&m); llong sum = 0ll;for(int i=1; i<=n; i++) {scanf("%lld",&a[i].x);}for(int i=1; i<=m; i++) {scanf("%lld%lld%lld",&b[i].x,&b[i].c,&b[i].w); sum += b[i].w;}if(sum<n) {printf("-1"); return 0;}int i = 1,j = 1;while(i<=n||j<=m){if(i<=n && (j>m||a[i].x<b[j].x)) {insertmouse(a[i].x); i++;}else {inserthole(b[j].x,b[j].w,b[j].c); j++;}}printf("%lld\n",ans);return 0;
}

UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)相关推荐

  1. [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流

    题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...

  2. UOJ #455.【UER #8】雪灾与外卖 堆模拟费用流

    题意 有n个人和m家商店,每个人都要买一道菜.第i个人的坐标是a[i],第j家商店的坐标是y[i],有c[i]道菜且每道菜价格为w[i],每个人还要花费其到商店距离的路费,问最小花费. n,m≤105 ...

  3. 【贪心+堆/模拟费用流增广】BZOJ4946 [NOI2017]蔬菜

    一道思路很好的题,因为篇幅太长赶时间,以下多数转自这里 [题目] 定义了一种蔬菜为: a i , s i , c i , x i a_i,s_i,c_i,x_i ai​,si​,ci​,xi​,有 n ...

  4. 【贪心 / 线段树模拟费用流增广】BZOJ4977 [Lydsy八月月赛] 跳伞求生

    [题目] 原题地址 有nn个队友和mm个敌人,每个队友有一个攻击力aia_i,每个敌人有攻击力bib_i和价值cic_i.你可以选择若干个队友,每个队友ii分别去怼一个敌人jj,当ai>bja_ ...

  5. 【2018山东省赛 - A】Anagram(贪心,费用流,KM算法)

    题干: Problem Description Orz has two strings of the same length: A and B. Now she wants to transform ...

  6. 校内hu测(10.6T2,T3)(乱搞+贪心+模拟)

    @liu_runda T2.便(then) [题目描述] 给出一个R*C的棋盘.共有R行C列,R*C个格子.现要在每个格子都填一个非负整数.使得任意一个2*2的正方形区域都满足这样的性质:左上角的数字 ...

  7. 【NOIP2013】积木大赛(差分数组,贪心模拟)

    题目 原题链接 问题描述 分析 直观思路--贪心模拟:每次都处理最长正整数区段. 以[2,3,4,1,2][2,3,4,1,2][2,3,4,1,2]为例: [2,3,4,1,2]⟹[1,2,3,0, ...

  8. 【UOJ#389】【UNR#3】白鸽(欧拉回路,费用流)

    [UOJ#389][UNR#3]白鸽(欧拉回路,费用流) 题面 UOJ 题解 首先第一问就是判断是否存在一条合法的欧拉回路,这个拿度数和连通性判断一下就行了. 第二问判断转的圈数,显然我们只需要考虑顺 ...

  9. 【UOJ455】【UER #8】雪灾与外卖

    [题目链接] 点击打开链接 [思路要点] 首先判断是否无解,以下讨论默认问题有解. 令 ∞\infty∞ 为一个足够大的数,对于送餐员 XiX_iXi​ ,在 Xi−∞X_i-\inftyXi​−∞ ...

最新文章

  1. CCF201612-4 压缩编码(100分)
  2. 快评《19家网站内容低俗被曝光》
  3. 2018/Province_Java_A/2/星期一
  4. 2013年第四届蓝桥杯C/C++ A组国赛 —— 第二题:骰子迷题
  5. custom configuration DB and creation logic
  6. Linux 字符设备驱动开发基础(四)—— ioctl() 函数解析
  7. python logging模块的作用及应用场景_Python常用模块功能简介(三)logging
  8. java压缩与解压缩
  9. 分布式一致性算法2PC和3PC
  10. Image Upload based on jQuery
  11. python中debug和run有什么区别_android应用程序开发中run和debug 有什么区别?
  12. 简易计算器的c++实现
  13. 计算机网络最短路径算法SPF,spf算法(spf算法计算最短路径)
  14. 组成原理之全加器实验
  15. linux pam鉴定令牌错误,linux – chsh:PAM身份验证失败
  16. 数理逻辑(一):逻辑学初步
  17. 使用conda安装pytorch时出现问题CondaSSLError: OpenSSL appears to be unavailable on this machine.
  18. Agent XPs disable
  19. cmd执行调用打开文件
  20. 随时标注各种物件,一个小标签机就能搞定,汉印M11体验

热门文章

  1. 台湾大学林轩田机器学习基石课程学习笔记7 -- The VC Dimension
  2. uboot更改gpio电平_ECBM系列教程4:单片机的手和脚——GPIO
  3. Eclipse中的插件安装
  4. 出现java.lang.UnsupportedClassVersionError 错误的原因
  5. linux文件的特殊权限,Linux系统文件的默认权限和特殊权限
  6. 【学习笔记】分布式Tensorflow
  7. How to Build Your Own Blockchain Part 4.1 — Bitcoin Proof of Work Difficulty Explained
  8. Android Telephony分析(二) ---- RegistrantList详解
  9. 使用Android studio 创建svn分支
  10. threadlocal使用_Java多线程数据共享神器ThreadLocal