1. 程式人生 > >6437 Problem L.Videos (最小費用最大流)

6437 Problem L.Videos (最小費用最大流)

C-bacteria takes charge of two kinds of videos: ’The Collection of Silly Games’ and ’The Collection of Horrible Games’. 
For simplicity’s sake, they will be called as videoA and videoB. 
There are some people who want to watch videos during today, and they will be happy after watching videos of C-bacteria. 
There are n hours a day, m videos are going to be show, and the number of people is K. 
Every video has a type(videoA or videoB), a running time, and the degree of happi- ness after someone watching whole of it. 
People can watch videos continuous(If one video is running on 2pm to 3pm and another is 3pm to 5pm, people can watch both of them). 
But each video only allows one person for watching. 
For a single person, it’s better to watch two kinds to videos alternately, or he will lose W happiness. 
For example, if the order of video is ’videoA, videoB, videoA, videoB, …’ or ’B, A, B, A, B, …’, he won’t lose happiness; But if the order of video is ’A, B, B, B, A, B, A, A’, he will lose 3W happiness. 
Now you have to help people to maximization the sum of the degree of happiness.

Input

Multiple query. 
On the first line, there is a positive integer T, which describe the number of data. Next there are T groups of data. 
for each group, the first line have four positive integers n, m, K, W : n hours a day, m videos, K people, lose W happiness when watching same videos). 
and then, the next m line will describe m videos, four positive integers each line S, T, w, op : video is the begin at S and end at T, the happiness that people can get is w, and op describe it’s tpye(op=0 for videoA and op=1 for videoB). 
There is a blank line before each groups of data. 
T<=20, n<=200, m<=200, K<=200, W<=20, 1<=S<T<=n, W<=w<=1000, 
op=0 or op=1 

Output

Your output should include T lines, for each line, output the maximum happiness for the corresponding datum.

Sample Input

2
10 3 1 10
1 5 1000 0
5 10 1000 1
3 9 10 0
10 3 1 10
1 5 1000 0
5 10 1000 0
3 9 10 0

Sample Output

2000
1990

          這道題就是說n人可以去看m場電影,看一場電影會獲得快樂值,連續看同一型別的電影會損失快樂值,求安排後能獲得的最大的快樂值。(每個電影只能一個人看)

         最小費用最大流,將電影拆點,拆點間流量為1,價值為電影獲得快樂值,然後一個究極源點到一個超級源點,流量就是人數n,價值是0。然後所有的電影末點與超級匯點一個流量為1,價值為0的連結。最後是每個電影都可以與他之後播放的電影相連線,如果型別一樣的話,價值為-w,否則為w。

         最後求的是最大的快樂之,再把之前步驟裡所有的價值取反得結果即可。

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1200;
const int maxm = 100050;
const int inf = 0x3f3f3f3f;
struct fuck {
	int v, ne, cap, flow, cost, u;
}ed[maxm];
struct fucker {
	int st, en, v, kind;
}spot[maxn];
int head[maxn], cnt;
int pre[maxn], dis[maxn];
bool vis[maxn];
int en, m, N;
void init() {
	cnt = 0;
	memset(head, -1, sizeof(head));
}
void add(int u, int v, int cap, int cost) {
	ed[cnt].v = v; ed[cnt].cap = cap; ed[cnt].flow = 0; ed[cnt].u = u;
	ed[cnt].cost = cost; ed[cnt].ne = head[u]; head[u] = cnt++;
	ed[cnt].v = u; ed[cnt].cap = 0; ed[cnt].flow = 0; ed[cnt].u = v;
	ed[cnt].cost = -cost; ed[cnt].ne = head[v]; head[v] = cnt++;
}
bool spfa(int st, int en) {
	queue<int>q;
	for (int s = 0; s <= en; s++) {//這裡視情況而定
		dis[s] = inf; vis[s] = 0; pre[s] = -1;
	}
	dis[st] = 0;
	vis[st] = 1;
	q.push(st);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		vis[u] = 0;
		for (int s = head[u]; ~s; s = ed[s].ne) {
			int v = ed[s].v;
			if (ed[s].cap > ed[s].flow&&dis[v] > dis[u] + ed[s].cost) {
				dis[v] = dis[u] + ed[s].cost;
				pre[v] = s;
				if (!vis[v]) {
					vis[v] = 1; q.push(v);
				}
			}
		}
	}
	if (pre[en] == -1)return 0;
	return 1;
}
int MinMax(int st, int en, int &cost) {
	int flow = 0;
	cost = 0;
	while (spfa(st, en)) {		
		int min = inf;
		for (int s = pre[en]; ~s; s = pre[ed[s ^ 1].v]) {
	
			if (min > ed[s].cap - ed[s].flow)
				min = ed[s].cap - ed[s].flow;
		}
		for (int s = pre[en]; ~s; s = pre[ed[s ^ 1].v]) {
			ed[s].flow += min;
			ed[s ^ 1].flow -= min;
			cost += ed[s].cost*min;
		}
		flow += min;
	}
	return flow;
}
int main() {
	int te;
	scanf("%d", &te);
	while (te--) {
		init();
		int m, n, sum, publish;
		scanf("%d%d%d%d", &m, &n, &sum, &publish);
		for (int s = 1; s <= n; s++)
			scanf("%d%d%d%d", &spot[s].st, &spot[s].en, &spot[s].v, &spot[s].kind);
	    en = 2 * n + 2;
		for (int s = 1; s <= n; s++) {
			add(s, s+n, 1, -spot[s].v);
			add(0, s, 1, 0);
			add(s+n, en, 1, 0);
			for (int w = 1; w <= n; w++) {
				if (s == w)continue;
				if (spot[s].en <= spot[w].st)
					add(s + n, w, 1, publish*(spot[s].kind == spot[w].kind ? 1 : 0));
			}
		}
		N = 2 * n + 1;
		add(N, 0, sum, 0);
		int cost;
		MinMax(N, en, cost);
		printf("%d\n", -cost);
	}
}