DestinHistoire

 

BZOJ-2465 [中山市选2009]小球(最大费用最大流)

题目描述

  给定 \(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\),费用为 \(p_i\) 的边;若 \(p_i\leq q_j\),每个球 \(i\) 向每个瓶子 \(j\) 连一条容量为 \(1\),费用为 \(0\) 的边;每个瓶子 \(j\) 向汇点 \(T\) 连一条容量为 \(c_j\),费用为 \(0\) 的边。跑一次 \(\text{SPFA}\) 找增广路就相当于放了一个球。

代码

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

posted on 2020-12-02 12:36  DestinHistoire  阅读(55)  评论(0编辑  收藏  举报

导航