zoukankan      html  css  js  c++  java
  • P3358 最长k可重区间集问题

    题目链接 (Click) (Here)

    这题的写法非常巧妙。

    每个位置的点向它的下一个位置连一个容量为(INF)的边,从区间的左端点往右端点拉一条容量为(1),费用为区间长度的边,从起点向点(1)连一条容量为(k)的边,限制只能流(k)次。这个建模的巧妙之处就在,它并没有明面上限制某个点最多经过(k)次,却实际上使路径单向,从而每一次流过都最多经过每个点一次,同时也并不会对并没有相交的区间造成影响。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100010;
    const int M = 400010;
    const int INF = 0x3f3f3f3f;
    
    int n, k, tot, l[N], r[N], len[N], pos[N];
    
    int cnt = -1, head[N];
    
    struct edge {
    	int nxt, to, w, f;
    }e[M];
    
    void add_edge (int from, int to, int flw, int val) {
    	e[++cnt].nxt = head[from];
    	e[cnt].to = to;
    	e[cnt].w = val;
    	e[cnt].f = flw;
    	head[from] = cnt;
    }
    
    void add_len (int u, int v, int f, int w) {
    	add_edge (u, v, f, +w);
    	add_edge (v, u, 0, -w);
    }
    
    void discretize () {
    	for (int i = 1; i <= n; ++i) {
    		cin >> l[i] >> r[i];
    		len[i] = r[i] - l[i];
    		pos[i * 2 - 1] = l[i], pos[i * 2] = r[i];
    	}
    	sort (pos + 1, pos + 1 + n * 2);
    	tot = unique (pos + 1, pos + 1 + n * 2) - pos - 1;
       	for (int i = 1; i <= n; ++i) {
    		l[i] = lower_bound (pos + 1, pos + 1 + tot, l[i]) - pos;
    		r[i] = lower_bound (pos + 1, pos + 1 + tot, r[i]) - pos;
    	}
    }
    
    queue <int> q;
    int dis[N], vis[N], flow[N];
    int pre_node[N], pre_edge[N];
    
    int spfa (int s, int t) {
    	memset (vis, 0, sizeof (vis));
    	memset (dis, -0x3f, sizeof (dis));
    	memset (flow, 0x3f, sizeof (flow));
    	q.push (s); vis[s] = true; dis[s] = 0;
    	while (!q.empty ()) {
    		int u = q.front (); q.pop ();
    		for (int i = head[u]; ~i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (dis[v] < dis[u] + e[i].w && e[i].f) {
    				dis[v] = dis[u] + e[i].w;
    				flow[v] = min (flow[u], e[i].f);
    				pre_edge[v] = i;
    				pre_node[v] = u;
    				if (!vis[v]) {
    					vis[v] = true;
    					q.push (v);
    				}
    			}
    		}
    		vis[u] = false;
    	}
    	return dis[t] != dis[0];
    }
    
    int main () {
    	memset (head, -1, sizeof (head));
    	cin >> n >> k;
    	discretize ();
    	int s = tot + 1, t = tot + 2;
    	add_len (s, 1, k, 0);
    	add_len (tot, t, k, 0);
    	for (int i = 1; i < tot; ++i) {
    		add_len (i, i + 1, INF, 0);
    	}
    	for (int i = 1; i <= n; ++i) {
    		add_len (l[i], r[i], 1, len[i]);
    	}
    	int max_cost = 0;
    	while (spfa (s, t)) {
    		max_cost += dis[t] * flow[t];
    		int u = t;
    		while (u != s) {
    			e[pre_edge[u] ^ 0].f -= flow[t];
    			e[pre_edge[u] ^ 1].f += flow[t];
    			u = pre_node[u];
    		}
    	}
    	cout << max_cost << endl;
    } 
    
    
  • 相关阅读:
    [ SDOI 2006 ] 保安站岗
    [ TJOI 2012 ] 防御
    [ ZJOI 2012 ] 灾难
    [ HNOI 2008 ] 玩具装箱
    「UER#2」信息的交换
    「UR#5」怎样跑得更快
    「UR#6」懒癌
    清华集训2014 做题记录
    「UR#5」怎样更有力气
    弦图及区间图学习笔记
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10478144.html
Copyright © 2011-2022 走看看