题解 洛谷 P4177 【[CEOI2008]order】

进行分析后,发现最大收益可以转化为最小代价,那么我们就可以考虑用最小割来解决这道题。

先算出总收益\(sum\),总收益减去最小代价即为答案。

然后考虑如何建图,如何建立最小割的模型。

发现一个任务最终的处理只有两种情况:

① 不完成这个任务,那么我们需要支付\(val\)的代价。

② 完成这个任务,若任务中某个工序用租的方式来解决,则需要支付其租金的代价,若用买的方式来解决,则需要支付其购买费用的代价,且以后可以使用这台机器。

那么最小割的模型就可以建立了。

从源点\(S\)向每个任务连边,容量为收益\(val\),割边表示不完成这个任务。

从每个任务向其所对应的机器连边,容量为租金,割边表示租机器来完成工序。

从每个机器向汇点\(T\)连边,容量为购买的费用,割边表示购买机器。

边的数组记得开大,实现细节就看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 3000010
#define inf 200000000
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,s,t,sum;
struct edge
{
    int to,nxt,v;
}e[maxn];
int head[maxn],edge_cnt=1;
void add(int from,int to,int val)
{
    e[++edge_cnt]=(edge){to,head[from],val};
    head[from]=edge_cnt;
    e[++edge_cnt]=(edge){from,head[to],0};
    head[to]=edge_cnt;
}
int d[maxn],cur[maxn];
bool bfs()
{
    for(int i=s;i<=t;++i) cur[i]=head[i];
    memset(d,0,sizeof(d));
    d[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to,v=e[i].v;
            if(d[y]||!v) continue;
            d[y]=d[x]+1;
            q.push(y);
        }
    }
    return d[t];
}
int dfs(int x,int lim)
{
    if(x==t) return lim;
    int flow,res=lim;
    for(int &i=cur[x];i;i=e[i].nxt)
    {
        int y=e[i].to,v=e[i].v;
        if(d[y]!=d[x]+1||!v) continue;
        if(flow=dfs(y,min(res,v)))
        {
            res-=flow;
            e[i].v-=flow;
            e[i^1].v+=flow;
            if(!res) break;
        }
    }
    return lim-res;
}
int dinic()
{
    int ans=0,flow;
    while(bfs())
        while(flow=dfs(s,inf))
            ans+=flow;
    return ans;
}
int main()
{
    read(n),read(m),t=n+m+1;
    for(int i=1;i<=n;++i)
    {
        int val,k;
        read(val),read(k);
        sum+=val,add(s,i,val);
        for(int j=1;j<=k;++j)
        {
            int num,cost;
            read(num),read(cost);
            add(i,n+num,cost);
        }
    }
    for(int i=1;i<=m;++i)
    {
        int cost;
        read(cost);
        add(n+i,t,cost);
    }
    printf("%d",sum-dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lhm-/p/12229869.html