题目大意:有$n$个小时,有$m$个节目(每种节目都有类型$0/1$),有$k$个人,一个人连续看相同类型的节目会扣$w$快乐值。
每一种节目有都一个播放区间$[l,r]$。每个人同一时间只能看一个节目,第$i$个节目只能一个人看,看完可以获得快乐$val_i$。问最多可以获得多少快乐?
题解:最大费用最大流,为了保证每个影片只被一个人观看,将其拆为入点和出点,入点和出点之间连一条容量为$1$,花费为$0$的边。
建一个源点$ST$和次源点$st$。从$ST$向$st$建一条容量为$k$,花费为$0$的边,表示有$k$个人可以看影片。
从$st$点向每个入点连一条容量为$1$,花费为$val_i$的边,若两个影片的时间不相交($T_u \leqslant S_v$),那么在$u$到$v$之间建一条容量为$1$,花费为$val_v$的边;若$u,v$属性相同则花费为$val_v-W$。
最后将每个出点向汇点连一条容量为$1$,花费为$0$的边。
卡点:1.不知道为啥数组开小(计算出来不会锅)
2.换电脑的时候代码未保存,把一份错误代码复制了过去(调了我一天)
C++ Code:
#include
#include
#define maxn 1010
#define maxm 50100
const int inf = 0x3f3f3f3f;
int Tim;
int n, m, K, W, st, ed;
struct node {
int S, T, w, ty;
} s[maxn];
int q[maxn], h, t;
int d[maxn], pre[maxn];
bool vis[maxn];
int head[maxn], cnt = 2;
struct Edge {
int to, nxt, w, cost;
} e[maxm << 1];
void add(int a, int b, int c, int d) {
e[cnt] = (Edge) {b, head[a], c, d}; head[a] = cnt;
e[cnt ^ 1] = (Edge) {a, head[b], 0, -d}; head[b] = cnt ^ 1;
cnt += 2;
}
inline int min(int a, int b) {return a < b ? a : b;}
bool spfa() {
for (int i = st; i <= ed; i++) d[i] = -inf;
d[q[h = t = 0] = st] = 0;
while (h <= t) {
int u = q[h++];
vis[u] = false;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (e[i].w && d[v] < d[u] + e[i].cost) {
d[v] = d[u] + e[i].cost;
pre[v] = i;
if (!vis[v]) {
q[++t] = v;
vis[v] = true;
}
}
}
}
return d[ed] != -inf;
}
int update() {
int ans, mf = inf;
for (int i = pre[ed]; i; i = pre[e[i ^ 1].to]) mf = min(mf, e[i].w);
ans = mf * d[ed];
for (int i = pre[ed]; i; i = pre[e[i ^ 1].to]) e[i].w -= mf, e[i ^ 1].w += mf;
return ans;
}
void MCMF() {
int ans = 0;
while (spfa()) ans += update();
printf("%d\n", ans);
}
int main() {
scanf("%d", &Tim);
while (Tim --> 0) {
scanf("%d%d%d%d", &n, &m, &K, &W);
st = 0; ed = m + 1 << 1;
add(st, 1, K, 0);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d%d", &s[i].S, &s[i].T, &s[i].w, &s[i].ty);
add(i << 1, i << 1 | 1, 1, 0);
add(1, i << 1, 1, s[i].w);
add(i << 1 | 1, ed, 1, 0);
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (i != j && s[i].T <= s[j].S) add(i << 1 | 1, j << 1, 1, (s[i].ty == s[j].ty) ? s[j].w : s[j].w - W);
}
}
MCMF();
if (Tim) memset(head, 0, sizeof head), cnt = 2;
}
return 0;
}