BZOJ 2879 美食节(费用流-动态加边)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2879

题意:有n道菜,每道菜需要b[i]份,m个厨师,第j个厨师做第i道菜需要时间a[i][j],求做完所有菜,所有人等待的最小总时间。

思路:设所有的菜为sum。一个明显的思路是将每个厨师拆成sum个点。然后sum个菜每个菜向每个厨师的每个点连边,表示该道菜为该厨师第几个做。由于这样数据太大。动态加边。每次增光一次后找到此次增广的厨师,每道菜将其连边。

 

struct node

{

    int u,v,next,cost,cap;

};









node edges[N*5];

int head[N],e;









void add(int u,int v,int cap,int cost)

{

    e++;

    edges[e].u=u;

    edges[e].v=v;

    edges[e].cap=cap;

    edges[e].cost=cost;

    edges[e].next=head[u];

    head[u]=e;

}













void Add(int u,int v,int cap,int cost)

{

    add(u,v,cap,cost);

    add(v,u,0,-cost);

}

















int pre[N],F[N],C[N],visit[N];









int SPFA(int s,int t,int n)

{

    int i;

    for(i=0;i<=n;i++) F[i]=0,C[i]=INF,visit[i]=0;

    queue<int> Q;

    Q.push(s); F[s]=INF; C[s]=0;

    int u,v,cost,cap;

    while(!Q.empty())

    {

        u=Q.front();

        Q.pop();

        

        visit[u]=0;

        for(i=head[u];i;i=edges[i].next)

        {

            if(edges[i].cap>0)

            {

                v=edges[i].v;

                cost=edges[i].cost;

                cap=edges[i].cap;

                if(C[v]>C[u]+cost)

                {

                    C[v]=C[u]+cost;

                    F[v]=min(F[u],cap);

                    pre[v]=i;

                    if(!visit[v]) visit[v]=1,Q.push(v);

                }

            }

        }

    }

    return F[t];

}









int s,t,n,m,a[55][105],b[105],cnt[105],last[105];





int main()

{

    RD(n,m);

    int sum=0,i,j,x;

    FOR1(i,n) RD(b[i]),sum+=b[i];

    e=1;

    s=0; t=n+m+sum+1;

    FOR1(i,n) 

    {

        Add(s,i,b[i],0);

        FOR1(j,m) 

        {

            RD(a[i][j]);

            Add(i,n+j,1,a[i][j]);

        }

    }

    FOR1(i,m)

    {

        cnt[i]=1;

        Add(n+i,t,1,0);

        last[i]=e;

    }

    int ans=0,temp;

    while(sum--)

    {

        temp=SPFA(s,t,t);

        for(i=t;i!=s;i=edges[pre[i]].u)

        {

            x=pre[i];

            ans+=temp*edges[x].cost;

            edges[x].cap-=temp;

            edges[x^1].cap+=temp;

        }

        for(j=1;j<=m&&edges[last[j]-1].cap;j++);

        cnt[j]++;

        FOR1(i,n) Add(i,n+m+sum,1,a[i][j]*cnt[j]);

        Add(n+m+sum,t,1,0);

        last[j]=e;

    }

    PR(ans);

}

 

 

 

你可能感兴趣的:(ZOJ)