BZOJ 1391 order

本文介绍了一种解决最大权闭合子图问题的方法,通过构建特定的网络流图并利用Dinic算法求解最小割,从而得到最大利润。问题背景为在不同机器和工序的组合下,通过购买或租赁机器完成工作任务以实现利益最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

有N个工作,M种机器,每种机器你可以租或者买过来.每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成。现在给出这些参数,求最大利润

解析:

这道题一看就是最大权闭合子图,如果不考虑可以购买这种操作,那和太空飞行计划那道题是一样的了。考虑到购买一件机器后就不用再租用它,那么我们只要在机器和汇点之间连一条流量为购买费用的边,其他边正常构建,用总的利益减去最小割即可。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 0x7fffffff
using namespace std;
int T,n,m,cnt=1,ans,cur[2501],q[2505],head[2505],h[2505];
struct data{int to,next,v;}e[3000001];
void ins(int u,int v,int w)
{cnt++;e[cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,0);}
bool bfs()
{
     int t=0,w=1,i,now;
     for(int i=1;i<=T;i++)h[i]=-1;
     q[0]=h[0]=0;
     while(t!=w)
     {
            now=q[t];t++;if(t==2501)t=0;
            for(i=head[now];i;i=e[i].next)
            {
                  if(e[i].v&&h[e[i].to]<0)
                        {h[e[i].to]=h[now]+1;q[w++]=e[i].to;if(w==2501)w=0;}
             }
     }
     if(h[T]==-1)return 0;return 1;
     }
int dfs(int x,int f)
{
    if(x==T)return f;
    int w,used=0;
    for(int i=cur[x];i;i=e[i].next)
    {
            if(e[i].v&&h[e[i].to]==h[x]+1)
            {
                w=f-used;
                w=dfs(e[i].to,min(w,e[i].v));   
                e[i].v-=w;if(e[i].v>0)cur[x]=i;e[i^1].v+=w;
                used+=w;if(used==f)return f;                      
                }
            }
    if(!used)h[x]=-1;
    return used;
    }
void dinic(){while(bfs()){for(int i=0;i<=T;i++)cur[i]=head[i];ans-=dfs(0,inf);}}
int main()
{
    scanf("%d%d",&n,&m);
    T=n+m+1;
    int a,b,c,d;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a,&b);
        insert(0,i,a);ans+=a;
        for(int j=1;j<=b;j++)
        {
            scanf("%d%d",&c,&d);
            insert(i,n+c,d);
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a);
        insert(n+i,T,a);
    }
    dinic();
    printf("%d",ans);
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值