POJ2047 Concert Hall Scheduling(最小费用最大流)

时间:2023-12-13 22:18:20

题目大概是有两个音乐厅,有n个乐队申请音乐厅,他们必须从第ii天到第ji天连续开音乐会且他们的开价是wi,每天每个音乐厅都只能供一个乐队进行音乐会。问接受哪些乐队的申请,获利最多能多少。

这题相当于在一条数轴上选择最大权和的线段,使两两相交的线段不超过两个。POJ3680,区间k覆盖。

先把每个申请的时间段处理成左闭右开的区间,然后离散化,建容量网络,跑MCMF即可。

 #include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 1111
#define MAXM 1111*1111*2
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int vs,vt,NV,NE,head[MAXN];
void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v;
edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u;
edge[NE].cap=; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
int d[MAXN],pre[MAXN];
bool vis[MAXN];
bool SPFA(){
for(int i=; i<NV; ++i){
d[i]=INF; vis[i]=;
}
d[vs]=; vis[vs]=;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=;
que.push(v);
}
}
}
vis[u]=;
}
return d[vt]!=INF;
}
int MCMF(){
int res=;
while(SPFA()){
int flow=INF,cost=;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int x[],y[],w[],point[],pn;
int getposi(int a){
return lower_bound(point,point+pn,a)-point;
}
int main(){
int n;
while(~scanf("%d",&n) && n){
pn=;
for(int i=; i<n; ++i){
scanf("%d%d%d",x+i,y+i,w+i);
point[pn++]=x[i];
point[pn++]=++y[i];
}
sort(point,point+pn);
pn=unique(point,point+pn)-point;
vs=pn; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
addEdge(vs,,,); addEdge(pn-,vt,,);
for(int i=; i<pn; ++i){
addEdge(i-,i,INF,);
}
for(int i=; i<n; ++i){
addEdge(getposi(x[i]),getposi(y[i]),,-w[i]);
}
printf("%d\n",-MCMF());
}
return ;
}