题目大概是有两个音乐厅,有n个乐队申请音乐厅,他们必须从第ii天到第ji天连续开音乐会且他们的开价是wi,每天每个音乐厅都只能供一个乐队进行音乐会。问接受哪些乐队的申请,获利最多能多少。
这题相当于在一条数轴上选择最大权和的线段,使两两相交的线段不超过两个。POJ3680,区间k覆盖。
先把每个申请的时间段处理成左闭右开的区间,然后离散化,建容量网络,跑MCMF即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 1111 8 #define MAXM 1111*1111*2 9 struct Edge{ 10 int u,v,cap,cost,next; 11 }edge[MAXM]; 12 int vs,vt,NV,NE,head[MAXN]; 13 void addEdge(int u,int v,int cap,int cost){ 14 edge[NE].u=u; edge[NE].v=v; 15 edge[NE].cap=cap; edge[NE].cost=cost; 16 edge[NE].next=head[u]; head[u]=NE++; 17 edge[NE].u=v; edge[NE].v=u; 18 edge[NE].cap=0; edge[NE].cost=-cost; 19 edge[NE].next=head[v]; head[v]=NE++; 20 } 21 int d[MAXN],pre[MAXN]; 22 bool vis[MAXN]; 23 bool SPFA(){ 24 for(int i=0; i<NV; ++i){ 25 d[i]=INF; vis[i]=0; 26 } 27 d[vs]=0; vis[vs]=1; 28 queue<int> que; 29 que.push(vs); 30 while(!que.empty()){ 31 int u=que.front(); que.pop(); 32 for(int i=head[u]; i!=-1; i=edge[i].next){ 33 int v=edge[i].v; 34 if(edge[i].cap && d[v]>d[u]+edge[i].cost){ 35 d[v]=d[u]+edge[i].cost; 36 pre[v]=i; 37 if(!vis[v]){ 38 vis[v]=1; 39 que.push(v); 40 } 41 } 42 } 43 vis[u]=0; 44 } 45 return d[vt]!=INF; 46 } 47 int MCMF(){ 48 int res=0; 49 while(SPFA()){ 50 int flow=INF,cost=0; 51 for(int u=vt; u!=vs; u=edge[pre[u]].u){ 52 flow=min(flow,edge[pre[u]].cap); 53 } 54 for(int u=vt; u!=vs; u=edge[pre[u]].u){ 55 edge[pre[u]].cap-=flow; 56 edge[pre[u]^1].cap+=flow; 57 cost+=flow*edge[pre[u]].cost; 58 } 59 res+=cost; 60 } 61 return res; 62 } 63 int x[1111],y[1111],w[1111],point[2222],pn; 64 int getposi(int a){ 65 return lower_bound(point,point+pn,a)-point; 66 } 67 int main(){ 68 int n; 69 while(~scanf("%d",&n) && n){ 70 pn=0; 71 for(int i=0; i<n; ++i){ 72 scanf("%d%d%d",x+i,y+i,w+i); 73 point[pn++]=x[i]; 74 point[pn++]=++y[i]; 75 } 76 sort(point,point+pn); 77 pn=unique(point,point+pn)-point; 78 vs=pn; vt=vs+1; NV=vt+1; NE=0; 79 memset(head,-1,sizeof(head)); 80 addEdge(vs,0,2,0); addEdge(pn-1,vt,2,0); 81 for(int i=1; i<pn; ++i){ 82 addEdge(i-1,i,INF,0); 83 } 84 for(int i=0; i<n; ++i){ 85 addEdge(getposi(x[i]),getposi(y[i]),1,-w[i]); 86 } 87 printf("%d ",-MCMF()); 88 } 89 return 0; 90 }