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;
}