BZOJ-1391: [Ceoi2008]order

[文章目录]

Description

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

网络流最小割(纳尼?我居然把板子敲错了,不可饶恕)
源点向每个工作连边,流量为收益,工作向租用机器连边,流量为租金,机器向汇点连边,流量为购买价格。总收益减去最小割就是答案。
然而,亲测TLE。。。然后网上说要加一个什么当前弧优化(在dinic算法中)。也挺简单的,就是每次在寻找增广路径的时候,到达一个点,直接从其没有搜过的边开始搜索,对于搜过的边,由于已经满流,所以没有必要扫。
对于每个点记录一个数组cur[x],表示x点第一个没有被搜过的出边,在搜索的时候直接更新cur的值。注意,每次bfs之后需初始化cur数组(cur[i]=head[i])。

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,s,t,ans;
int head[2500],cur[2500],nxt[3300000],to[3300000],f[3300000],cnt=1;
inline void add(int x,int y,int z)
{
    to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; f[cnt]=z;
    to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt; f[cnt]=0;
}
queue<int>q;
int dis[2500];
bool bfs()
{
    memset(dis,-1,sizeof dis);
    while(!q.empty()) q.pop();
    dis[s]=0; int x; q.push(s);
    while(!q.empty())
    {
        x=q.front(); q.pop();
        for(int i=head[x];i;i=nxt[i]) if(f[i]>0&&dis[to[i]]==-1)
        {
            dis[to[i]]=dis[x]+1;
            if(to[i]==t) return true;
            q.push(to[i]);
        }
    }
    return false;
}
int dinic(int x,int flow)
{
    if(x==t) return flow;
    int xx,tmp=flow;
    for(int &i=cur[x];i;i=nxt[i]) if(f[i]>0&&dis[to[i]]==dis[x]+1)
    {
        xx=dinic(to[i],min(f[i],tmp));
        if(!xx) dis[to[i]]=-1;
        f[i]-=xx; f[i^1]+=xx; tmp-=xx;
        if(!tmp) return flow;
    }
    return flow-tmp;
}
int main()
{
    scanf("%d%d",&n,&m); s=n+m+1; t=s+1;
    int x,y,z;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&x,&z);
        ans+=x; add(s,i,x);
        while(z--)
        {
            scanf("%d%d",&x,&y);
            add(i,n+x,y);
        }
    }
    for(int i=1;i<=m;++i)
    {
        scanf("%d",&x);
        add(n+i,t,x);
    }
    while(bfs())
    {
        for(int i=1;i<=t;++i) cur[i]=head[i];
        ans-=dinic(s,inf);
    }
    printf("%d",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注