luogu P4177 [CEOI2008]order |最大权闭合子图

题目描述

\(N\) 个工作,\(M\) 种机器,每种机器可以租或者买。每个工作包括若干道工序,每道工序需要某种机器来完成。

你需要最大化利益。

输入格式

第一行给出 \(N,M\)

接下来若干行描述一个工作,对于每个工作,第一行给定 \(x_i\)\(t_i\)​,分别表示此工作的收入和工序数。

后面 \(t_i\)​ 行,每行两个整数 \(a_{ij}\)​ 和 \(b_{ij}\)​,分别表示此工序需要的机器和此工作租用此机器的费用。

最后 \(M\) 行,每行一个正整数表示购买机器的费用 \(y_i\)

输出格式

最大利润


基本上是最大权闭合子图的模板

租借操作就把inf改权值

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2505,M=N*N,inf=1<<30;
int nxt[M],head[N],go[M],edge[M],tot=1;
inline void add(int u,int v,int w){
    nxt[++tot]=head[u],head[u]=tot,go[tot]=v,edge[tot]=w;
    nxt[++tot]=head[v],head[v]=tot,go[tot]=u,edge[tot]=0;
}
int n,m,s,t,maxflow;
int d[N],now[N];
bool bfs(){
    queue<int>q;
    memset(d,0,sizeof(d));
    q.push(s); d[s]=1;
    now[s]=head[s];
    while(q.size()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=nxt[i]){
            int v=go[i];
            if(edge[i]&&!d[v]){
                q.push(v);
                d[v]=d[u]+1;
                now[v]=head[v];
                if(v==t)return 1;
            }
        }
    }
    return 0;
}
int dinic(int u,int flow){
    if(u==t)return flow;
    for(int &i=now[u];i;i=nxt[i]){
        int v=go[i];
        if(edge[i]&&d[v]==d[u]+1){
            int k=dinic(v,min(flow,edge[i]));
            if(!k)d[v]=0;
            else{
                edge[i]-=k;
                edge[i^1]+=k;
                return k;
            }
        }
    }
    return 0;
}
signed main(){
    cin>>n>>m;
    s=0,t=n+m+1;
    int ans=0;
    for(int i=1,x,y,z;i<=n;i++){
        scanf("%d%d",&x,&y);
        add(s,i,x);
        ans+=x;
        while(y--){
            scanf("%d%d",&x,&z);
            add(i,n+x,z);
        }
    }
    for(int i=1,x;i<=m;i++){
        scanf("%d",&x);
        add(n+i,t,x);
    }
    int flow=0;
    while(bfs())
    while(flow=dinic(s,inf))maxflow+=flow;
    cout<<ans-maxflow<<endl;
    
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12918736.html