将每场电影拆成两个点,从入点向出点连边,费用是h,容量为1。从源点向它的入点、它的出点向汇点连边,费用为0,容量为1。
考虑到m很小,可以O(m^2)地在电影之间连边。如果i的结束时间不晚于j的开始时间,那么就从i的出点带j的入点连边,容量为1,若i和j为同类费用为w,否则费用为0。
最后将源点也拆成两个点,从入点到出点连边,容量为k,费用为0,表示一共只有k个人。
这样就是一个最大费用最大流的问题。存边的时候费用取负值然后跑最小费用最大流即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 20050;
const int INF = 0x3f3f3f3f;
const ll mod = 10000000007;
int T, n, m, k, w, no, s, t, st, ans;
int head[maxn], dis[maxn], pre[maxn];
bool vis[maxn];
struct point
{
int l, r;
int f, id;
}p[maxn];
struct node
{
int to, nxt;
int cap, flow, cost;
}e[maxn];
void add(int a, int b, int w, int x)
{
e[no].to = b, e[no].nxt = head[a];
e[no].cost = w, e[no].cap = x, e[no].flow = 0;
head[a] = no++;
e[no].to = a, e[no].nxt = head[b];
e[no].cost = -w, e[no].cap = 0, e[no].flow = 0;
head[b] = no++;
}
bool spfa(int s, int t)
{
queue<int>q;
for(int i = 0;i <= t;i++)
dis[i] = INF, vis[i] = 0, pre[i] = -1;
dis[s] = 0, vis[s] = 1;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u];i != -1;i = e[i].nxt)
{
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] = 1;
q.push(v);
}
}
}
}
return (pre[t] != -1);
}
int MinCostMaxFlow(int s, int t, int &cost)
{
int flow = 0;
cost = 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;
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d%d", &n, &m, &k, &w);
no = 0;
memset(head, -1, sizeof(head));
s = 0, t = m*2 + 2, st = m*2 + 1;
for(int i = 1;i <= m;i++)
{
scanf("%d%d%d%d", &p[i].l, &p[i].r, &p[i].f, &p[i].id);
add(i, i + m, -p[i].f, 1);
add(i + m, t, 0, 1);
add(st, i, 0, 1);
}
add(s, st, 0, k);
for(int i = 1;i <= m;i++)
{
for(int j = 1;j <= m;j++)
{
if(i == j) continue;
if(p[i].r <= p[j].l)
{
if(p[i].id == p[j].id) add(i + m, j, w, 1);
else add(i + m, j, 0, 1);
}
}
}
ans = 0;
int res = MinCostMaxFlow(s, t, ans);
printf("%d\n", -ans);
}
return 0;
}