P3358 最长k可重区间集问题

P3358 最长k可重区间集问题

题目链接

输入最多500个点对,即离散化后最多有1000个坐标。

对离散化后的坐标建图。

方法一: 将坐标从小到大连边,一个点与它后面相邻的点建一条边(流量为inf,花费为0),点对的左端点与右端点建一条边(流量为1,花费为(-区间长度)),s与第一个点建一条边(流量为k,花费为0),最后一个点与t建一条边(流量为k,花费为0)
方法二: s与s'之间建一条边(流量为k,花费为0),s'与各区间左端点之间建一条边(流量为1,花费为0),区间左端点向本区间的右端点建一条边(流量为1,花费为(-区间长度)),区间右端点与比它大的区间左端点建边(流量为1,花费为0),各区间右端点与t建一条边(流量为1,花费为0)

方法一代码:

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int maxn = 10010;
const int maxm = 100010;
const int inf = 0x3f3f3f3f;
struct edge {
    int to, next, cap, flow, cost;
} e[maxm];
int head[maxn], tot;
int pre[maxn], dis[maxn];
bool vis[maxn];
int N;

void init(int n) {
    N = n;
    tot = 1;
    memset(head, 0, sizeof(head));
}

void addedge(int u, int v, int cap, int cost) {
    e[++tot].to = v, e[tot].next = head[u], e[tot].cap = cap, e[tot].cost = cost, e[tot].flow = 0, head[u] = tot;
    e[++tot].to = u, e[tot].next = head[v], e[tot].cap = 0, e[tot].flow = 0, e[tot].cost = -cost, head[v] = tot;
}

bool spfa(int s, int t) {
    deque<int> q;
    for (int i = 0; i <= N; ++i) {
        dis[i] = inf;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push_front(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop_front();
        vis[u] = 0;
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if (e[i].cap > e[i].flow && dis[v] > dis[u] + e[i].cost) {
                dis[v] = dis[u] + e[i].cost;
                pre[v] = i;
                if (!vis[v]) {
                    vis[v] = true;
                    if (!q.empty()) {
                        if (dis[v] < dis[q.front()]) q.push_front(v);
                        else q.push_back(v);
                    } else q.push_back(v);
                }
            }
        }
    }
    return pre[t] != -1;
}

int mcfc(int s, int t, int &cost) {
    cost = 0;
    int flow = 0;
    while (spfa(s, t)) {
        int minn = inf;
        for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
            if (minn > e[i].cap - e[i].flow) {
                minn = e[i].cap - e[i].flow;
            }
        }
        for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
            e[i].flow += minn;
            e[i ^ 1].flow -= minn;
            cost += e[i].cost * minn;
        }
        flow += minn;
    }
    return flow;
}

vector<int> X;
int A[maxn], B[maxn], C[maxn];

int main() {
    X.clear();
    init(1010);
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> A[i] >> B[i];
        C[i] = B[i] - A[i];
        X.push_back(A[i]);
        X.push_back(B[i]);
    }

    //离散化
    sort(X.begin(), X.end());
    X.erase(unique(X.begin(), X.end()), X.end());

    int s = 0, t = X.size() - 1;

    for (int i = 0; i < t; i++)
        addedge(i, i + 1, inf, 0);

    for (int i = 0; i < n; i++) {
        int a = lower_bound(X.begin(), X.end(), A[i]) - X.begin();
        int b = lower_bound(X.begin(), X.end(), B[i]) - X.begin();
        addedge(a, b, 1, -C[i]);
    }
    int ans;
    s = X.size(), t = s + 1;
    addedge(s, 0, k, 0);
    addedge(X.size() - 1, t, k, 0);
    mcfc(s, t, ans);
    cout << -ans << endl;
    return 0;
}

方法二代码:

//其余代码与上面相同
int main() {
    X.clear();
    init(10000);
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> A[i] >> B[i];
        C[i] = B[i] - A[i];
        X.push_back(A[i]);
        X.push_back(B[i]);
    }

    //离散化
    sort(X.begin(), X.end());
    X.erase(unique(X.begin(), X.end()), X.end());
    int s = X.size(), t = s + 2, s1 = s + 1;
    addedge(s, s1, k, 0);

    for (int i = 0; i < n; i++) {
        int a = lower_bound(X.begin(), X.end(), A[i]) - X.begin();
        int b = lower_bound(X.begin(), X.end(), B[i]) - X.begin();
        addedge(a, b, 1, -C[i]);
        addedge(s1, a, 1, 0);
        addedge(b, t, 1, 0);
        for (int j = 1; j < n; j++) {
            int c = lower_bound(X.begin(), X.end(), A[j]) - X.begin();
            if (b <= c) addedge(b, c, 1, 0);
        }
    }
    int ans;

    mcfc(s, t, ans);
    cout << -ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/albert-biu/p/11291644.html