网络流二十四题 最长 k 可重区间集

来源:互联网 发布:广场舞下载软件 编辑:程序博客网 时间:2024/06/06 07:34

Poweroj和codevs上数据都有问题,点这里可以提交:https://oj.hsefz.info/problem/13
题意:记一个开区间 z=(L,R) 的长度 |Z|=RL 。给定实直线 Ln 个开区间组成的集合 I ,和一个正整数 k ,试设计一个算法,从开区间集合 I 中选取出开区间集合 SI ,使得在实直线 L 上任意一点 xS 中包含点 x 的开区间个数不超过 k,且 zS|z| 达到最大。这样的集合 S 称为开区间 I 的最长 k 可重区间集,zS|z| 称为最长 k 可重区间集的长度。
对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k 可重区间集的长度。1n500 ,1k3
这个问题可以看作从头到尾选 k 次,每次选不相交的一些区间,那么不取可以在没费用的路上一段一段走过去,取可以走有费用的边。
先把节点离散化,相邻节点 ii+1 之间连流量 INF,费用为 0 的边。
对与每个区间在数轴上连一条流量 1 ,费用 RL 的边。
S 向第一个节点和 最后一个节点到 T 都连流量 INF,费用为 0 的边。
SS 连一条 流量为 k 费用为 0 的边表示流量限制。

#include<bits/stdc++.h>const int N = 20050;const int INF = 1e9;template <typename T> void read(T &x) {    x = 0; char c = getchar();    for (; !isdigit(c); c = getchar());    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';}struct edge {    int x, y, f, v, next;}mp[N * 10];int n, k, l[N], r[N], a[N], b[N], first[N], s, q[N + 9], from[N], S, _S, T;bool inq[N];long long dis[N], ans;void ins(int x, int y, int f, int v) {    //printf("ins x=%d y=%d f=%d v=%d\n", x, y, f, v);    mp[++s] = (edge) {x, y, f, v, first[x]}; first[x] = s;    mp[++s] = (edge) {y, x, 0, -v, first[y]}; first[y] = s;}bool SPFA() {    for (int i=S; i <= T; i++) dis[i] = 1, inq[i] = 0;    int head = 1, tail = 2;    inq[q[head] = S] = 1;    dis[q[head]] = 0;    while (head != tail) {        int x = q[head];        //printf("x=%d\n", x);        for (int t=first[x]; t; t=mp[t].next) {            //printf("y=%d\n", mp[t].y);            if (mp[t].f && dis[x] + mp[t].v < dis[mp[t].y]) {                dis[mp[t].y] = dis[x] + mp[t].v;                from[mp[t].y] = t;                if (!inq[mp[t].y]) {                    inq[q[tail++] = mp[t].y] = 1;                    if (tail > N) tail = 1;                }            }        }        inq[q[head++]] = 0;        if (head > N) head = 1;    }    return dis[T] != 1;}void mcf() {    int fl = INF;    for (int x=T; x != S; x = mp[from[x]].x)        fl = std::min(fl, mp[from[x]].f);    for (int x=T; x != S; x = mp[from[x]].x)        mp[from[x]].f -= fl,        mp[from[x]^1].f += fl;    ans += dis[T] * fl;}int find(int x) {    int l = 1, r = n * 2;    while (l < r) {        int mid = (l + r + 1) / 2;        if (a[mid] > x)            r = mid - 1;        else            l = mid;    }    return b[l];}int main() {    read(n); read(k);    for (int i=1; i <= n; i++) {        read(l[i]), read(r[i]);        if (l[i] > r[i]) std::swap(l[i], r[i]);        a[i*2-1] = l[i], a[i*2] = r[i];    }    std::sort(a+1, a+n*2+1);    for (int i=1; i <= n * 2; i++)        b[i] = b[i - 1] + (i == 1 || a[i] > a[i - 1]);    S = 0; _S = b[n * 2] + 1; T = b[n * 2] + 2; s = 1;    for (int i=1; i < b[n * 2]; i++)        ins(i, i + 1, INF, 0);    for (int i=1; i <= n; i++)        ins(find(l[i]), find(r[i]), 1, -(r[i] - l[i]));    ins(S, _S, k, 0);    ins(_S, 1, INF, 0);    ins(b[n * 2], T, INF, 0);    while (SPFA()) mcf();    printf("%lld\n", -ans);    return 0;}
阅读全文
0 0
原创粉丝点击