(又是一道简单的最小费用流的题目)
题目大概意思为有N个带权的开区间,现在从中选取一些区间,使任意点都不能被超过k个区间覆盖,求最大权重和
首先我们求得是最大的权重和,所以我们把 权重 ,看为 -权重 ,来求最小费,最后求个绝对值即可
然后每个区间只能选一次,考虑拆点,每个点拆为两个,连接一条容量为1,费用为 -权重
设置一个超级源点和超级汇点连接每个点,边的容量为1,费用为0(因为不确定从哪个区间开始覆盖,和从哪个区间结束)
将两个不相交(b[i] <= a[i])的区间相连,容量为1,费用为0(这样便可以正确连接图上有关系的点)
设置流最大为k,即意思为不能被超过k个区间覆盖
最后套用最小费用流模板即可
(注意当dist[to] == INF,即起点无法到终点时,提前返回res即可)
#include <stdio.h>
#include <iostream>
#include <vector>
#define INF 1000000005
using namespace std;
int n, k;
int a[205], b[205], w[205];
struct edge
{
int to, cap, coust, rev;
edge(int t, int c, int s, int r)
{
to = t; cap = c; coust = s; rev = r;
}
};
vector<struct edge> ddd[505];
int dist[505];
int prev[505];
int prep[505];
void add_edge(int from, int to, int cap, int coust)
{
ddd[from].push_back(edge(to, cap, coust, ddd[to].size()));
ddd[to].push_back(edge(from, 0, -coust, ddd[from].size() - 1));
}
int min_coust(int from, int to, int flow)
{
int res = 0;
while(flow > 0)
{
fill(dist, dist + n + n + 2, INF);
dist[from] = 0;
bool flag = true;
while(flag)
{
flag = false;
for(int i = 0; i < n + n + 2; i++)
{
if(dist[i] != INF)
{
for(int j = 0; j < ddd[i].size(); j++)
{
struct edge e = ddd[i][j];
if(e.cap != 0 && dist[i] + e.coust < dist[e.to])
{
flag = true;
dist[e.to] = dist[i] + e.coust;
prev[e.to] = i;
prep[e.to] = j;
}
}
}
}
}
if(dist[to] == INF)
{
return res;
}
int d = flow;
for(int i = to; i != from; i = prev[i])
{
d = min(d, ddd[prev[i]][prep[i]].cap);
}
for(int i = to; i != from; i = prev[i])
{
ddd[prev[i]][prep[i]].cap -= d;
ddd[i][ddd[prev[i]][prep[i]].rev].cap += d;
}
res = res - dist[to] * d;
flow = flow - d;
}
return res;
}
int main()
{
int N;
scanf("%d", &N);
while(N--)
{
for(int i = 0; i < 2 * n + 2; i++)
{
ddd[i].clear();
}
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++)
{
scanf("%d %d %d", &a[i], &b[i], &w[i]);
}
for(int i = 1; i <= n; i++)
{
add_edge(0, i, 1, 0);
add_edge(i, n + i, 1, -w[i]);
add_edge(n + i, n + n + 1, 1, 0);
for(int j = i + 1; j <= n; j++)
{
if(b[i] <= a[j])
{
add_edge(i + n, j, 1, 0);
}
else if(a[i] >= b[j])
{
add_edge(j + n, i, 1, 0);
}
}
}
printf("%d\n", min_coust(0, n + n + 1, k));
}
}