题目大意:一个著名的音乐厅因为财务状况恶化快要破产,你临危受命,试图通过管理的手段来拯救它,方法之一就是优化演出安排,即聪明的决定接受和拒绝哪些乐团的演出申请,使得音乐厅的收益最大化。该音乐厅有两个完全相同的房间,因此各乐团在申请演出的时候并不会指定房间,你只需要随便分配一个即可。每个演出都会持续若干天,每个房间每天只能举行一场演出。申请数目n为不超过1000的正整数,每个申请用三个整数i, j, w描述,表示从第i天演到第j天,愿意支付w元。
题目分析:这道题还是重点在于建模,主要是k覆盖模型,想一下,每个区间划分为[i,j),但是每一个演出都只能在一家音乐厅演出,所以在i—>j+1上建边(i,j+1,1,-w),然后366天,第i—>i+1天建边(i,i+1,2,0),超级源点s:(s,1,2,0),超级汇点t=366
然后从最左边跑到最右边最小费用最大流即可。
区间 k 覆盖模型。
区间 k 覆盖问题。数轴上有一些带全值的左闭右开区间,选出权和尽量大的一些区间,使得任意一个数最多被 k 个区间覆盖。
解:首先这是可以用最小费用流解决的。构图方法是把每个数作为一个结点,然后对于权值为 w 的区间[ u,v ),建边u -> v,容量为1,费用为 -w。在对所有相邻的点建边 i -> i + 1,容量为 k,费用为0。最后,求最左点到最右点的最小费用最大流即可,其中每个流量对应一组互不相交的区间。如果数值范围太大,可以先离散化。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define clear(A, X) memset(A, X, sizeof A)
#define min(A, B) ((A) < (B) ? (A) : (B))
using namespace std;
const int maxE = 2000000;
const int maxN = 2048;
const int oo = 0x3f3f3f3f;
struct Edge{
int v, c, w, n;
Edge(){}
Edge(int V, int C, int W, int N) : v(V), c(C), w(W), n(N){}
};
struct Node{
int l, r, w;
};
Edge edge[maxE];
Node sche[maxN];
int adj[maxN], cntE;
int Q[maxE], head, tail;
int d[maxN], inq[maxN], cur[maxN], f[maxN];
int cost, flow, s, t;
int n;
void addedge(int u, int v, int c, int w){
edge[cntE] = Edge(v, c, w, adj[u]); adj[u] = cntE++;
edge[cntE] = Edge(u, 0, -w, adj[v]); adj[v] = cntE++;
}
int spfa(){
clear(d, oo);
clear(inq, 0);
cur[s] = -1;
f[s] = oo;
d[s] = 0;
head = tail = 0;
Q[tail++] = s;
inq[s] = 1;
while(head != tail){
int u = Q[head++];
inq[u] = 0;
for(int i = adj[u]; ~i; i = edge[i].n){
int v = edge[i].v, c = edge[i].c, w = edge[i].w;
if(c && d[v] > d[u] + w){
d[v] = d[u] + w;
f[v] = min(f[u], c);
cur[v] = i;
if(!inq[v]){
Q[tail++] = v;
inq[v] = 1;
}
}
}
}
if(d[t] == oo) return 0;
flow += f[t];
cost += d[t] * f[t];
for(int i = cur[t]; ~i; i = cur[edge[i ^ 1].v]){
edge[i].c -= f[t];
edge[i ^ 1].c += f[t];
}
return 1;
}
int MCMF(){
flow = cost = 0;
while(spfa());
return cost;
}
void init(){
clear(adj, -1);
cntE = 0;
}
void build(){
s = 0; t = n * 2 + 3;
int s1 = n * 2 + 1, s2 = n * 2 + 2;
addedge(s, s1, 1, 0);
addedge(s, s2, 1, 0);
for(int i = 1; i <= n; ++i) scanf("%d%d%d", &sche[i].l, &sche[i].r, &sche[i].w);
for(int i = 1; i <= n; ++i){
addedge(s1, i, 1, 0);
addedge(s2, i, 1, 0);
addedge(i, i + n, 1, -sche[i].w);
addedge(i + n, t, 1, 0);
for(int j = 1; j <= n; ++j){
if(sche[i].r < sche[j].l) addedge(i + n, j, 1, 0);
}
}
}
void work(){
init();
build();
printf("%d\n", -MCMF());
}
int main(){
while(~scanf("%d", &n) && n) work();
return 0;
}