BZOJ2465: [中山市选2009]小球
Description
给定n个不同颜色的球,每个球都有一个分数,同时有m个瓶子,每个瓶子都有固定的容量。现在,你必须把球放到瓶子里面。请编程计算最多能放多少个球到这些瓶子里。
Input
输入包含多组数据。
每组数据的第一行为两个整数n, m,分别表示球的个数和瓶子的个数。
接下来的n行,每一行包含一个整数p,表示相应的球的分数。
接下来的m行,每一行包含两个整数c和q, 分别表示每个瓶子的容量(最多能装多少个球)和分数上界(放进该瓶子的每个球的分数都不能超过去q)。
当输入n,m均为0时,表示输入结束。
Output
对于每组数据,输出两个整数B和S,分别表示总共能放进瓶子里的球的最大数目,以及在这个前提下,放进瓶子里面的所有球的最大分数总和。B和S以空格隔开,每组答案独占一行。
Sample Input
2 1
2
3
1 2
2 2
4
5
2 4
2 5
0 0
2
3
1 2
2 2
4
5
2 4
2 5
0 0
Sample Output
1 2
2 9
2 9
HINT
对于全部的数据,有1<=n<=200,0<=m<=200,1 <= p <= 10^6, 0 <= c <= 200, 1 <= q <= 10^6.
看来只有我这样的doubi才会萌萌哒地写费用流。
直接上ZKW费用流,将小球和盒子分别按分数排序,填上一些边。。。
模板一遍打对还是很开心的。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; const int inf=1000000000; const int maxn=510; const int maxm=20010; struct ZKW { int n,m,s,t,inq[maxn],d[maxn]; int first[maxn],next[maxm]; struct Edge {int from,to,flow,cost;}edges[maxm]; ll cost,ans; void init(int n) { this->n=n;m=0; memset(first,-1,sizeof(first)); } void AddEdge(int u,int v,int w,int cost) { edges[m]=(Edge){u,v,w,cost};next[m]=first[u];first[u]=m++; edges[m]=(Edge){v,u,0,-cost};next[m]=first[v];first[v]=m++; } int Q[maxn*100],vis[maxn]; int BFS() { rep(i,1,n) d[i]=inf;d[t]=0; int l=1,r=0;Q[++r]=t; while(l<=r) { int x=Q[l++];inq[x]=0; ren { Edge& e=edges[i^1]; if(e.flow&&d[e.from]>d[x]+e.cost) { d[e.from]=d[x]+e.cost; if(!inq[e.from]) inq[e.from]=1,Q[++r]=e.from; } } } rep(i,0,m-1) edges[i].cost+=d[edges[i].to]-d[edges[i].from]; cost+=d[s];return d[s]!=inf; } int DFS(int x,int a) { if(x==t||!a) {ans+=a*cost;return a;} int f,flow=0;vis[x]=1; ren { Edge& e=edges[i]; if(e.flow&&!e.cost&&!vis[e.to]&&(f=DFS(e.to,min(a,e.flow)))) { e.flow-=f;edges[i^1].flow+=f; flow+=f;a-=f;if(!a) break; } } return flow; } void solve(int s,int t) { this->s=s;this->t=t; cost=ans=0;int flow=0,tmp; while(BFS()) do { memset(vis,0,sizeof(vis)); flow+=(tmp=DFS(s,inf)); }while(tmp); printf("%d %lld\n",flow,-ans); } }sol; int A[maxn]; struct Bottle { int c,q; bool operator < (const Bottle& ths) const {return q>ths.q;} }B[maxn]; int main() { while(1) { int n=read(),m=read(),s=n+m+1,t=n+m+2;sol.init(n+m+2); if(!n&&!m) break; rep(i,1,n) A[i]=read(); rep(i,1,m) B[i].c=read(),B[i].q=read(); sort(A+1,A+n+1);sort(B+1,B+m+1); rep(i,1,n) { sol.AddEdge(s,i,1,-A[i]); int j=1;while(j<=m&&B[j].q>=A[i]) j++; if(j!=1) sol.AddEdge(i,j+n-1,1,0); } rep(i,1,m) { if(i!=1) sol.AddEdge(i+n,i+n-1,inf,0); sol.AddEdge(i+n,t,B[i].c,0); } sol.solve(s,t); } return 0; }