#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> #include <map> using namespace std; const int maxn = 500; const int maxm = 1E5 + 10; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow, cost; }; Edge edge[maxm]; int head[maxn], tol, pre[maxn], dis[maxn], n, k, m, a[maxn], b[maxn], w[maxn], res[maxm], T, cnt; bool vis[maxn]; void addedge(int u, int v, int cost, int cap) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s, int t) { queue<int>q; memset(dis, INF, sizeof(dis)); memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); dis[s] = 0; vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } return (pre[t] == -1 ? false : true); } int MinCostMaxFlow(int s, int t, int &cost) { int flow = 0; cost = 0; while (spfa(s, t)) { int Min = INF; for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) Min = min(Min, edge[i].cap - edge[i].flow); for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } return flow; } int main(int argc, char const *argv[]) { scanf("%d", &T); while (T--) { cnt = 0, tol = 0; memset(head, -1, sizeof(head)); memset(res, -1, sizeof(res)); scanf("%d%d", &n, &k); for (int i = 0; i < n; i++) scanf("%d%d%d", &a[i], &b[i], &w[i]), res[a[i]] = 0, res[b[i]] = 0; for (int i = 0; i < maxm; i++) if (res[i] == 0) res[i] = ++cnt; for (int i = 0; i < cnt; i++) addedge(i + 1, i + 2, 0, INF); for (int i = 0; i < n; i++) addedge(res[a[i]], res[b[i]], -w[i], 1); addedge(0, 1, 0, k); addedge(cnt, cnt + 1, 0, k); int ans = 0; MinCostMaxFlow(0, cnt + 1, ans); printf("%d\n", -ans); } return 0; }
题意:给定n个带权开区间,选择其中一些使得权值最大并且区间重叠层数不超过k。
题解:最小费用流,区间有两百个,可以用左边的点发出一条到右边的点的边,容量为1,费用为负的权值。然后从左往右将依次将相邻的两个点都连起来,权值为0,容量为k,也就是说,如果选了这个区间,就会从费用为负数的边流过去,否则,就是从这个费用为0的边流过去。然后建立一个虚拟源点与最左边的点相连,权值为0,容量为k,这样就保证了重叠数之多为k,因为增广路上所经过的区间必定是不重合的,而流量只有k,所以满足题意。