题意:
有 k 个人看 m 个视频,一天有 n 个小时,每个视频只能一个人看,看完一个视频那个人会获得 W 快乐值,视频有自己的限制种类,视频种类相同一起看会扣 w 快乐值。问一天这群人最多可以获得多少快乐值。
题解:
我们可以想象 k 个人就是 k 流量,把一个视频想象成一个边,构成一个有源点和汇点,这样就可以跑最大费用最大流(把费用取负跑最小费用)。
AC代码
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <stack>
#include <cmath>
#include <deque>
#include <queue>
#include <list>
#include <set>
#include <map>
#define mem(a, b) memset(a, b, sizeof(a))
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 200000+10;
const int inf = 0x3f3f3f3f;
int tot, Next[maxn], dis[maxn], vis[maxn], pre[maxn], source, sink;
struct Edge{
int u, v, w, c, next;
Edge(){};
Edge(int _u, int _v, int _w, int _c, int _next){
u = _u;
v = _v;
w = _w;
c = _c;
next = _next;
}
}edge[maxn];
struct Film{
int l, r, w, op;
}film[200+10];
void add(int u, int v, int w, int c){
edge[tot] = Edge(u, v, w, c, Next[u]);
Next[u] = tot++;
edge[tot] = Edge(v, u, 0, -c, Next[v]);
Next[v] = tot++;
}
bool spfa(){
mem(vis, 0);
mem(dis, inf);
int l, r;
dis[source] = 0;
vis[source] = 1;
queue<int> q;
q.push(source);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = Next[u]; i != -1; i = edge[i].next){
int v = edge[i].v, w = edge[i].w, c = edge[i].c;
if(w > 0 && dis[v] > dis[u] + c){
dis[v] = dis[u] + c;
pre[v] = i;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
return dis[sink] != inf;
}
int update(){
int minn = inf;
for(int i = sink; i != source; i = edge[pre[i]].u){
minn = min(minn, edge[pre[i]].w);
}
for(int i = sink; i != source; i = edge[pre[i]].u){
edge[pre[i]].w -= minn;
edge[pre[i]^1].w += minn;
}
return minn*dis[sink];
}
int mcmf(){
int ans = 0;
while(spfa()){
ans += update();
}
return ans;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
tot = 0;
mem(Next, -1);
int n, m, k, w;
scanf("%d %d %d %d", &n, &m, &k, &w);
for(int i = 1; i <= m; i++){
scanf("%d %d %d %d", &film[i].l, &film[i].r, &film[i].w, &film[i].op);
}
source = 0;
sink = 2*m+k+1;
for(int i = 1; i <= m ; i++){
add(i, i+m, 1, -film[i].w);
add(i+m, sink, 1, 0);
for(int j = 1; j <= m; j++){
if(film[i].r <= film[j].l){
add(i+m, j, 1, film[i].op == film[j].op ? w : 0);
}
}
}
for(int i = 1; i <= k; i++){
add(source, i+2*m, 1, 0);
for(int j = 1; j <= m; j++){
add(i+2*m, j, 1, 0);
}
}
printf("%d\n", -mcmf());
}
}