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<=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;
}

时间: 2024-10-26 02:07:51

BZOJ2465: [中山市选2009]小球的相关文章

BZOJ 2466: [中山市选2009]树( 高斯消元 )

高斯消元解异或方程组...然后对自由元进行暴搜.树形dp应该也是可以的... -------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; const int ma

2463: [中山市选2009]谁能赢呢?

2463: [中山市选2009]谁能赢呢? Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 586[Submit][Status] Description 小明和小红经常玩一个博弈游戏.给定一个n×n的棋盘,一个石头被放在棋盘的左上角.他们轮流移动石头.每一回合,选手只能把石头向上,下,左,右四个方向移动一格,并且要求移动到的格子之前不能被访问过.谁不能移动石头了就算输.假如小明先移动石头,而且两个选手都以最优策略走步,问

bzoj2466: [中山市选2009]树

同上一题.(应该可以树形dp,然而我不会... #include<cstdio> #include<cstring> #include<iostream> #include<bitset> #include<algorithm> using namespace std; #define REP(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #

BZOJ2464: 中山市选[2009]小明的游戏

2464: 中山市选[2009]小明的游戏 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 280  Solved: 124[Submit][Status] Description 小 明最近喜欢玩一个游戏.给定一个n * m的棋盘,上面有两种格子#和@.游戏的规则很简单:给定一个起始位置和一个目标位置,小明每一步能向上,下,左,右四个方向移动一格.如果移动到同一类 型的格子,则费用是0,否则费用是1.请编程计算从起始位置移动到目标位置的最小花费.

【BZOJ2466】[中山市选2009]树 树形DP

[BZOJ2466][中山市选2009]树 Description 图论中的树为一个无环的无向图.给定一棵树,每个节点有一盏指示灯和一个按钮.如果节点的按扭被按了,那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭(当按之前是点亮的).并且该节点的直接邻居也发生同样的变化. 开始的时候,所有的指示灯都是熄灭的.请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态. Input 输入文件有多组数据. 输入第一行包含一个整数n,表示树的节点数目.每个节点的编号从1到n.

bzoj2463: [中山市选2009]谁能赢呢?

奇偶即可判断输赢 #include<cstdio> #include<cctype> int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } int main(){ int n; while(n=read()) { n%2?printf("Bob\n"):printf(

bzoj千题计划169:bzoj2463: [中山市选2009]谁能赢呢?

http://www.lydsy.com/JudgeOnline/problem.php?id=2463 n为偶数时,一定可以被若干个1*2 矩形覆盖 先手每次从矩形的一端走向另一端,后手每次走向一个新的矩形 所以先手必胜 n为奇数时,先手走完一步后,剩下同n为偶数 所以先手必败 #include<cstdio> using namespace std; int main() { int n; while(scanf("%d",&n)!=EOF) { if(!n)

bzoj2463: [中山市选2009]谁能赢呢?(博弈论)

2463: [中山市选2009]谁能赢呢? 题目:传送门 题解: 水体! n为偶数的话必能被1*2的矩形覆盖,那么因为一开始在左上角,所以先手一定可以先组成一个矩形,那么先手肯定必胜! n为奇数和上面相反,先手必输 代码: 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)!=EOF)

bzoj2464: 中山市选[2009]小明的游戏(最短路)

2464: 中山市选[2009]小明的游戏 题目:传送门 题解: 最短路的裸题... 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int dx[5]={0,1,-1,0,0}; 8 int dy[5]={0,0,0,-1,1}; 9 st