洛谷传送门
题目描述
对于给定的开区间集合 I I I 和正整数 k k k,计算开区间集合 I I I 的最长 k k k可重区间集的长度。
输入输出格式
输入格式:
输入的第 1 1 1 行有 2 2 2 个正整数 n n n和 k k k,分别表示开区间的个数和开区间的可重叠数。接下来的 n n n行,每行有 2 2 2 个整数,表示开区间的左右端点坐标。
输出格式:
将计算出的最长 k k k可重区间集的长度输出
输入输出样例
输入样例#1:
4 2
1 7
6 8
7 10
9 13
输出样例#1:
15
说明
对于100%的数据, 1 ≤ n ≤ 500 1\le n\le 500 1≤n≤500, 1 ≤ k ≤ 3 1\le k\le 3 1≤k≤3
解题分析
费用流经典模型, 还适用于一些需要线性规划转费用流的题目?
考虑将所有端点从小到大连流量为限制的边, 表示可以流过的流量。
从 l e f i lef_i lefi向 r i g i rig_i rigi连流量为 1 1 1, 花费为 r i g i − l e f i rig_i-lef_i rigi−lefi的边, 表示可以选这条边, 同时区间中可用流量 − 1 -1 −1。
最后跑一遍最大费用流即可。
端点可能很大, 需要离散化。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define INF 1e8
#define MX 1050
bool neg;
template <class C>
IN void in(C &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc)
if (c == '-') neg = true;
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
if (neg) neg = false, x = -x;
}
template <class C> IN C min(C a, C b) {return a < b ? a : b;}
int n, tot, dif, S, T, ans, k, cnt;
int head[MX], dis[MX], del[MX], pre[MX], from[MX], to[MX], buc[MX];
bool inq[MX];
struct Edge {int to, fl, len, nex;} edge[MX * 10];
IN void add(R int from, R int to, R int fl, R int len)
{
edge[++cnt] = {to, fl, len, head[from]}, head[from] = cnt;
edge[++cnt] = {from, 0, -len, head[to]}, head[to] = cnt;
}
namespace MCMF
{
std::queue <int> q;
IN bool SPFA()
{
std::memset(dis, 63, sizeof(dis));
dis[S] = 0, del[S] = INF, q.push(S);
R int now;
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if (dis[edge[i].to] > dis[now] + edge[i].len && edge[i].fl)
{
dis[edge[i].to] = dis[now] + edge[i].len;
pre[edge[i].to] = i;
del[edge[i].to] = min(del[now], edge[i].fl);
if (!inq[edge[i].to]) inq[edge[i].to] = true, q.push(edge[i].to);
}
}
inq[now] = false;
}
return dis[T] < INF;
}
void update()
{
R int now = T, pr;
W (now ^ S)
{
pr = pre[now];
edge[pr].fl -= del[T], edge[pr ^ 1].fl += del[T];
now = edge[pr ^ 1].to;
}
ans -= del[T] * dis[T];
}
void init()
{
W (SPFA()) update();
printf("%d", ans);
}
}
int main(void)
{
in(n), in(k);
std::memset(head, cnt = -1, sizeof(head));
for (R int i = 1; i <= n; ++i)
{
in(from[i]), in(to[i]);
buc[++tot] = from[i], buc[++tot] = to[i];
}
std::sort(buc + 1, buc + 1 + tot);
dif = std::unique(buc + 1, buc + 1 + tot) - buc - 1;
T = dif + 1;
for (R int i = 1; i <= dif; ++i) add(i - 1, i, k, 0);
add(dif, T, k, 0);
for (R int i = 1; i <= n; ++i) add(std::lower_bound(buc + 1, buc + 1 + dif, from[i]) - buc, std::lower_bound(buc + 1, buc + 1 + dif, to[i]) - buc, 1, -to[i] + from[i]);
MCMF::init();
}