C. Heidi and Library

题意

有 n 种分别具有价格 b 的书 a ,图书馆里最多同时存放 k 本书,已知接下来 n 天每天都有一个人来看某一本书,如果图书馆里没有则需要购买,问最少花费多少钱。

分析

这道题的一个简单版本 ,默认所有书价格为1,那么只需要用 set 维护一下,当图书馆内库存满的时候 erase 掉距离最大的书(贪心做法)。

但是有了价格之后,就不能贪心了,然后这道题就可以用神奇的网络流解决。准确的说是最小费用最大流。

所有边的容量为 1,将 n 个点拆成 2n 个点(2i,2i + 1),2i 和 2i + 1 连边,花费 -INF(因为求的最小费用,这里保证了 n 个点都会经过到),源点 S 连边 2i,费用为 b[a[i]] ,2i + 1 连边汇点 T,费用为 0 。遍历 n 个点,2i + 1 连边 2j ,如果 a[j] == a[i] ,费用为 0,否则费用为 b[a[j]]。

以上就是建图的过程,我们可以把 k 当作网络流的流量,以样例1为例。

4 80 // n k
1 2 2 1 // 看的书的种类
1 1 1 1 // 价格

当 k = 1 时,



首先最小费用流会保证一次跑完所有费用为 -INF 的边,保证了经过所有点,那么 k = 1 其实就是除非连续的几天种类相同,不然都要扔掉,买另一种书,我们在加边的时候已经处理了,比如相邻的边 (3 -> 4) 费用为 0。这种情况下花费为 3。



当 k = 2 时,引入新边 (S -> 2),它会走边(2 -> 1),这个边其实就是网络流提供给算法一种 “反悔” 的策略,如蓝色轨迹所示,其中(1 -> 2,2 -> 1)(5 -> 6,6 -> 5)两对边,全部抵消掉了。



那么其实在 k = 2 时,真正的策略如上图轨迹所示,我们可以将 k 当作 k 个放书的位置,每个位置互不影响,其中第一个位置存放 1 这本书,在第 0 天和第 3 天分别被借阅,第二个位置存放 2 这本书,在第 1 天和第 2 天分别被借阅 。

首先用 -INF 保证所有点都被按顺序访问到(第一次搜索时),在根据 k 的值,不断的做出 “反悔” 策略,最终达到最小费用。

注意:当判断到 dis[T] >= 0 时就要退出了,这个时候多加的 k 也毫无意义了。最后答案加上 n * INF。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10; //
const int MAXM = 2e5 + 5; // 注意扩张的边的数量
const ll INF = 1e9;
struct Edge {
int to, next, cap, flow, cost;
} edge[MAXM * 4];
int head[MAXN], tol;
int pre[MAXN];
ll dis[MAXN];
bool vis[MAXN];
int N;
void init(int n) {
N = n;
tol = 0;
memset(head, -1, sizeof head);
memset(pre, 0, sizeof pre);
memset(dis, 0, sizeof dis);
memset(vis, 0, sizeof vis);
memset(edge, 0, sizeof edge);
}
void addedge (int u, int v, int cap, int cost) {
edge[tol] = Edge{v, head[u], cap, 0, cost};
head[u] = tol++;
edge[tol] = Edge{u, head[v], 0, 0, -cost};
head[v] = tol++;
}
bool spfa(int s, int t) {
queue<int>q;
for(int i = 0; i < N; i++) {
dis[i] = INF * INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i]. to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
return dis[t] < 0;
}
int a[MAXN], b[MAXN];
int main() {
int n, k;
cin >> n >> k;
for(int i = 0; i < n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++) {
cin >> b[i];
}
init(MAXN);
int s = 2 * n, t = 2 * n + 1;
for(int i = 0; i < n; i++) {
addedge(s, 2 * i, 1, b[a[i]]);
addedge(2 * i + 1, t, 1, 0);
addedge(2 * i, 2 * i + 1, 1, -INF);
}
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
addedge(2 * i + 1, 2 * j, 1, a[i] == a[j] ? 0 : b[a[j]]);
}
}
ll cost = 0;
for(int i = 0; i < k; i++) {
if(!spfa(s, t)) break;
for(int j = pre[t]; j != -1; j = pre[edge[j^1].to]) {
edge[j].flow++;
edge[j^1].flow--;
}
cost += dis[t];
}
cout << cost + 1LL * n * INF<< endl;
return 0;
}

C. Heidi and Library (神奇的网络流)的更多相关文章

  1. 【CF802C】Heidi and Library(网络流)

    [CF802C]Heidi and Library(网络流) 题面 CF 洛谷 题解 前面两个Easy和Medium都是什么鬼玩意啊.... 不难发现如果这天的要求就是第\(a_i\)种书的话,那么\ ...

  2. 题解-CF802C Heidi and Library (hard)

    题面 CF802C Heidi and Library (hard) 有一个大小为 \(k\) 的空书架.有 \(n\) 天和 \(n\) 种书,每天要求书架中有书 \(a_i\).每天可以多次买书, ...

  3. CF802C Heidi and Library hard 费用流 区间k覆盖问题

    LINK:Heidi and Library 先说一下简单版本的 就是权值都为1. 一直无脑加书 然后发现会引起冲突,可以发现此时需要扔掉一本书. 扔掉的话 可以考虑扔掉哪一本是最优的 可以发现扔掉n ...

  4. 【CF802C】Heidi and Library (hard) 费用流

    [CF802C]Heidi and Library (hard) 题意:有n个人依次来借书,第i人来的时候要求书店里必须有种类为ai的书,种类为i的书要花费ci块钱购入.而书店的容量只有k,多余的书只 ...

  5. 贪心算法 Heidi and Library (easy)

    A. Heidi and Library (easy) time limit per test 2 seconds memory limit per test 256 megabytes input ...

  6. 【网络流】【待补】C. Heidi and Library (hard)

    http://codeforces.com/contest/802/problem/C

  7. 【网络流】codeforces C. Heidi and Library (hard)

    http://codeforces.com/contest/802/problem/C

  8. 洛谷P3159 交换棋子 神奇的网络流

    神奇的建模...原题链接 如果你真的把交换看成交换,就\(GG\)了.首先我们要把交换看成是白棋的移动. 然后,很容易的就想到建模的大致思路:建立超级源点S和超级汇点T,从S向初始局面每个白棋所在的格 ...

  9. CF.802C.Heidi and Library (hard) (费用流zkw)

    题目链接 复习了下餐巾计划问题.全忘了=-= 首先这是一道网络流.然后本题有\(n\)种建图方法,以及\(smy\) dalao还有单纯形做法. 先假设所有物品都是买入的.那么对于每一天,拆成两个点\ ...

随机推荐

  1. scp 将数据从一台linux服务器复制到另一台linux服务器

    原文地址:http://www.cnblogs.com/peida/archive/2013/03/15/2960802.html  完整内容参考原文! scp 是secure copy的简写,用于在 ...

  2. Python利器一之requests

    Python利器一之requests 一.教程涉及开发语言.脚本.框架.数据库等内容 Python + requests 通过 pip 安装: pip install requests 通过 easy ...

  3. json序列化datetime类型数据

    错误描述: import jsonimport datetime a = datetime.datetime.now()print(a) b = json.dumps(a)print(b) 如上代码, ...

  4. 孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化

    孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.什么是序列化与反序列化 序列化是指将内存中的数据进行指 ...

  5. 对于进程没杀死占用内存和cpu行为的方法

    在跑机器学习或者深度学习的过程中有可能遇到没杀死进程的情况,但是程序的入口又没关掉,尤其是我使用jupyter从远程Linux映射到windows浏览器跑程序的时候 对于上面的问题, 首先运行 hto ...

  6. 聊聊、Git 常用命令

    创建本地仓库git initgit add .git commit -m "xxxxx"git remote add origin http://git.xxx.com/xxx.g ...

  7. 锚点自适应 map area coords

    最近做MOBILE的HTML5开发,人体图和页面一样,需要自适应不同的手机屏幕,蛋疼的是coords里面的标记是固定的,图片自适应后,锚点的标记就会产生空白区域,看了下https://github.c ...

  8. CodeForces Round #515 Div.3 A. Vova and Train

    http://codeforces.com/contest/1066/problem/A Vova plans to go to the conference by train. Initially, ...

  9. MySQL之优化总结

    http://www.cnblogs.com/benshan/archive/2012/07/27/2612212.html MySQL之优化总结    今天,数据库的操作越来越成为整个应用的性能瓶颈 ...

  10. 新浪微博 page应用 自适应高度设定 终于找到解决方法

    我做的是PAGE应用,无法自适应高度.找了好久解决方法. 用js 设置父窗口 iframe 也不好用,有的浏览器不兼容. 官方上说发是这样的: 应用动态高度自适应 Iframe高度:开发者可以使Ifr ...