• UOJ455 雪灾与外卖(模拟费用流)


    UOJ455 雪灾与外卖(模拟费用流)

    题目大意

    给定一些老鼠,所有老鼠都要进洞,每个洞有容量限制和每进一只老鼠的代价,同时每个老鼠和洞都有坐标,老鼠走到洞还要付出距离的代价,最小化总代价

    数据范围

    (1 le n le 10^5)

    解题思路

    推荐大佬博客,因为学的他的,所以或许很相似

    这应该可以说是模拟费用流的经典题

    先考虑一些简单的问题

    下面默认所有坐标有序

    模型一

    所有老鼠向左走,每个洞里进一只,代价是距离,所有老鼠都进洞

    显然直接贪心即可,维护一个栈,每次老鼠去最近的

    模型二

    现在所有老鼠不一定进洞,并且每只老鼠进洞会付出 (w1[i]) 的代价,每只洞被进会付出 (w2[i]) 的代价

    注意这里的代价可负

    老鼠 i 进洞 j 的代价是 (w1[i]+w2[j]+x[i]-x[j] = (x[i]+w1[i])-(w2[j]+x[j]))

    显然我们用个堆维护即可

    模型三

    模型二的基础上必须全部进洞,那么直接把代价都减去 inf 最后在加上即可

    模型四

    模型二的基础上左走右走均可,这个问题就复杂些了

    从左到右模拟费用流,我们在后面加入一个老鼠或洞并用反悔(退流)操作维护当前最优解无标题

    维护两个堆 (q1, q2),分别表示待匹配老鼠和洞

    如果当前是老鼠,那么有三种操作

    • 等待后面的洞和它匹配

    • 和前面未匹配的洞匹配

    • 抢前面老鼠的洞

    如果当前是洞,那么也有三种操作

    • 等待后面的老鼠和它匹配
    • 和前面未匹配的老鼠匹配
    • 抢前面洞的老鼠

    我们可以把后面的两个操作合并起来做

    我们考虑洞的情况,那么老鼠的情况也将迎刃而解

    第一个操作是直接把 (w[i]-x[i]) 加入堆中

    第二三个操作是和老鼠发生匹配,那么以后有可能有老鼠来抢洞或者有洞来抢老鼠,我们需要提前考虑这两种情况

    有老鼠来抢洞,那么我们新增一个代价是 "(-k-2x[i])" 的洞

    有洞来抢老鼠,那么我们新增一个代价是 "-w[i]-x[i]" 的老鼠

    一个小细节是如果一个洞抢了老鼠,那么原先的洞不可能再被后面的老鼠抢到,因为老鼠和洞的连线时不可交叉的

    模型四

    加上容量和必选的条件,我们也可以轻松解决,必选直接在代价减去 inf,容量我们用 pair 存储即可,可能细节会多一些,这就是雪灾和外卖了

    代码

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x, char ed = '
    ')
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar(ed);
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 200500;
    const int inf = 1e9;
    struct node {
    	ll y, w, c; 
    }p[N];
    
    struct Pair {
    	ll x, y;
    	Pair(int xx = 0, int yy = 0) : x(xx), y(yy) {}
    	bool operator < (const Pair t) const {
    		return x == t.x ? y > t.y : x > t.x;
    	}
    };
    
    priority_queue<Pair> q1, q2;
    
    ll ans, x[N], res, m, n;
    int main() {
    //	freopen ("hs.in","r",stdin);
    	read(n), read(m);
    	for (int i = 1;i <= n; i++) read(x[i]);
    	for (int j = 1;j <= m; j++) 
    		read(p[j].y), read(p[j].w), read(p[j].c), res += p[j].c, p[j].w -= inf;
    	if (res < n) return puts("-1"), 0; 
    	int j = 1; x[n + 1] = 1e9;
    	for (int i = 1;i <= n + 1; i++) {
    		while (j <= m && p[j].y <= x[i]) {
    			ll sum = 0; 
    			while (p[j].c && q1.size()) {
    				Pair t1 = q1.top(); if (t1.x + p[j].w + p[j].y >= 0) break;
    				ll lim = min(p[j].c, t1.y); q1.pop();
    				ans += lim * (t1.x + p[j].w + p[j].y), sum += lim;
    				p[j].c -= lim, t1.y -= lim; if (t1.y) q1.push(t1);
    				q2.push(Pair(-t1.x - 2 * p[j].y, lim));
    			}
    			if (p[j].c) q2.push(Pair(-p[j].y + p[j].w, p[j].c));
    			if (sum) q1.push(Pair(-p[j].y - p[j].w, sum)); j++;
    		}
    		if (i > n) break;
    		if (q2.size()) {
    			Pair t2 = q2.top(); 
    			if (t2.x + x[i] >= 0) {
    				q1.push(Pair(-x[i], 1));
    				continue;
    			}
    			q2.pop(), ans += t2.x + x[i], t2.y--;
    			if (t2.y) q2.push(t2);
    			q2.push(Pair(-x[i], 1));
    			q1.push(Pair(-t2.x - 2 * x[i], 1));
    		}
    		else q1.push(Pair(-x[i], 1));
    	}
    	ans += (ll)n * inf, write(ans);
    	return 0;
    }
    
  • 相关阅读:
    CountDownLatch, CyclicBarrier, Semaphore
    工具类中使用@Autowired失败问题
    可重入锁(递归锁)
    读写锁
    自旋锁
    加入BLOG
    控制字符串的超长部分用省略号表示
    java常见面试题总结
    maven打包不运行test脚本的命令
    DataGrip使用教程
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13427326.html
Copyright © 2020-2023  润新知