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

Sample Output

1 2
2 9

HINT

对于全部的数据,有1<=n<=2000<=m<=2001 <= 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
",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;
}
View Code
原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5035064.html