2018 Multi-University Training Contest 10--HDU 6437 Problem L.Videos(最大費用最大流)

題意:

有 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());
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章