網絡流二十四題 最長 k 可重區間集

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章