「CEOI2008」order

题目链接

戳我

\(Solution\)

首先看看没有租条件的怎么弄.这很显然,就是普通最小割的套路
\(s\)向每个工作连一条流量\(x\)的边,\(x\)为工作收益
每个工作向每个机器连流量为\(inf\)的边
每个机器向\(T\)连流量为\(v\)的费用,\(v\)为买机器的费用
跑一遍最小割
答案就是\(\sum x-Dinic()\)
至于如果有租的条件,我们只需要将\(inf\)变成租的费用就好了

\(Code\)

#include<bits/stdc++.h>
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
const int inf=1e9;
typedef long long ll;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct node{
    int to,next,v;
}a[9000001];
int head[3410],cnt=1,n,m,s,t,x,y,z,dep[3410],sum,cur[3410];
inline void add(int x,int y,int c){
    a[++cnt].to=y,a[cnt].next=head[x],a[cnt].v=c,head[x]=cnt;
    a[++cnt].to=x,a[cnt].next=head[y],a[cnt].v=0,head[y]=cnt;
}
queue<int> q;
inline int bfs(){
    memset(dep,0,sizeof(dep)),q.push(s),dep[s]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=a[i].next){
            int v=a[i].to;
            if(!dep[v]&&a[i].v>0)
                dep[v]=dep[now]+1,q.push(v);
        }
    }
    return dep[t];
}
int dfs(int k,int list) {
    if(k==t||!list)
        return list;
    int flow=0;
    for(int i=head[k];i;i=a[i].next){
        int v=a[i].to;
        if(dep[v]==dep[k]+1&&a[i].v>0){
            int p=dfs(v,min(list,a[i].v));
            if(p){
                list-=p,flow+=p,a[i].v-=p,a[i^1].v+=p;
                if(!list)
                    break;
            }
        }
    }
    return flow;
}
void Dinic(){
    int ans=0,k;
    while(bfs())
		ans+=dfs(s,inf);
    printf("%d",sum-ans);
}
int main(){
    n=read(),m=read(),s=0,t=n+m+1;
    for(int i=1;i<=n;i++){
        x=read(),add(s,i,x),sum+=x,y=read();
        while(y--)
            x=read(),z=read(),add(i,x+n,z);
    }
    for(int i=1;i<=m;i++)
        x=read(),add(i+n,t,x);
    Dinic();
}
posted @ 2019-07-22 21:30  撤云  阅读(164)  评论(0编辑  收藏  举报
……