BZOJ-2465 [中山市選2009]小球(最大費用最大流)
阿新 • • 發佈:2020-12-02
題目描述
給定 \(n(1\leq n\leq 200)\) 個不同顏色的球,每個球 \(i\) 都有一個分數 \(p_i(1\leq p_i\leq 10^6)\),同時有 \(m(0\leq m\leq 200)\) 個瓶子,每個瓶子 \(j\) 都有容量 \(c_j(0\leq c_j\leq 200)\)(最多能裝多少個球) 和分數上界 \(q_j(1\leq q_j\leq 10^6)\)(放進該瓶子的每個球的分數都不能超過\(q_j\))。計算最多能放多少個球到這些瓶子裡,以及在這個前提下,放進瓶子裡面的所有球的最大分數總和。
分析
源點 \(S\) 向每個球 \(i\) 連一條容量為 \(1\)
程式碼
#include<bits/stdc++.h> using namespace std; const int N=5010,M=200010; int p[1010],c[1010],q[1010]; struct Edge { int to; int Next; int dis; int cost; }edge[M]; int head[N],dist[N],incf[N],pre[N],vis[N]; int n,m,S,T,num_edge,maxflow,maxcost; void add_edge(int from,int to,int dis,int cost) { edge[++num_edge].to=to; edge[num_edge].dis=dis; edge[num_edge].cost=cost; edge[num_edge].Next=head[from]; head[from]=num_edge; } bool SPFA() { queue<int> Q; memset(dist,0xcf,sizeof(dist)); memset(vis,0,sizeof(vis)); Q.push(S); dist[S]=0; vis[S]=1; incf[S]=1<<30; while(!Q.empty()) { int x=Q.front(); vis[x]=0; Q.pop(); for(int i=head[x];i;i=edge[i].Next) { if(!edge[i].dis) continue; int y=edge[i].to,z=edge[i].cost; if(dist[y]<dist[x]+z) { dist[y]=dist[x]+z; incf[y]=min(incf[x],edge[i].dis); pre[y]=i; if(!vis[y]) { vis[y]=1; Q.push(y); } } } } if(dist[T]==0xcfcfcfcf) return false; return true; } void update() { int x=T; while(x!=S) { int i=pre[x]; edge[i].dis-=incf[T]; edge[i^1].dis+=incf[T]; x=edge[i^1].to; } maxflow+=incf[T]; maxcost=maxcost+dist[T]*incf[T]; } int main() { while(cin>>n>>m&&n&&m) { memset(head,0,sizeof(head)); for(int i=1;i<=n;i++) scanf("%d",&p[i]); for(int i=1;i<=m;i++) scanf("%d %d",&c[i],&q[i]); S=n+m+1; T=n+m+2; num_edge=1; for(int i=1;i<=n;i++) { add_edge(S,i,1,p[i]); add_edge(i,S,0,-p[i]); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(p[i]<=q[j]) { add_edge(i,j+n,1,0); add_edge(j+n,i,0,0); } } } for(int j=1;j<=m;j++) { add_edge(j+n,T,c[j],0); add_edge(T,j+n,0,0); } maxflow=0;maxcost=0; while(SPFA()) update(); cout<<maxflow<<" "<<maxcost<<endl; } return 0; }