洛谷2050 BZOJ2897美食节题解

放个链接

BZ链接

其实这题就是修车的加强版,做法差不多,还是对于每个厨师进行拆点

可是这样强行建图跑网络流会T飞

我们发现,如果一个厨师没有做倒数第x到菜,他一定不会做倒数第x+1到菜

我们的每次增广表示有厨师的倒数第k道菜做了y,这样我们把这位厨师的倒数做k+1道菜的边连起来

动态加边

连边是注意每个点的意思是什么

# include<iostream>
# include<cstdio>
# include<algorithm>
# include<cmath>
# include<cstring>
# include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int mn = 100005;
int c[45][105],p[45];
struct edge{int to,next,flow,cost;};
edge e[3000005];
int head[mn],edge_max=1;
void add(int x,int y,int z,int k)
{
    //printf("%d %d %d %d\n",x,y,z,k);
    e[++edge_max].to=y;
    e[edge_max].flow=z;
    e[edge_max].cost=k;
    e[edge_max].next=head[x];
    head[x]=edge_max;
}
int n,m,sum;
int dis[mn],pe[mn],pv[mn],ansc,ansf;
bool vis[mn];
queue<int> q;
bool spfa(int x,int y)
{
    memset(dis,0x3f,sizeof(dis));
    dis[x]=0;
    q.push(x);
    while(!q.empty())
    {
        int u=q.front();
        vis[u]=0;
        q.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            if(e[i].flow>0 && e[i].cost+dis[u]<dis[e[i].to])
            {
                dis[e[i].to]=dis[u]+e[i].cost;
                pv[e[i].to]=u;
                pe[e[i].to]=i;
                if(!vis[e[i].to])
                {
                    vis[e[i].to]=1;
                    q.push(e[i].to);
                }
            }
        }
    }
    //for(int i=0;i<=y;i++)
    //printf("%d ",dis[y]);
    return dis[y]<inf;
}
void max_flow(int x,int y)
{
    int kflow,a,b;//a表示厨师编号
    while(spfa(x,y))
    {
        //printf("%d %d\n",ansc,ansf);
        kflow=inf;
        for(int i=y;i!=x;i=pv[i])
            kflow=min(kflow,e[pe[i]].flow);
        a=(pv[y]-1)/sum+1;
        b=pv[y]%sum+1;
        ansf+=kflow;
        ansc+=kflow*dis[y];
        for(int i=y;i!=x;i=pv[i])
        {
            e[pe[i]].flow-=kflow;
            e[pe[i]^1].flow+=kflow;
            //ansc+=kflow*e[pe[i]].cost;
        }
        for(int i=1;i<=n;i++)
            add(i+m*sum,(a-1)*sum+b,1,c[i][a]*b),add((a-1)*sum+b,i+m*sum,0,-c[i][a]*b);
    }
}
int main()
{
    int st=0;
    //freopen("testdata.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]),sum+=p[i];
    int en=sum*m+n+1;
   // printf("%d\n",en);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&c[i][j]);
    for(int i=1;i<=n;i++)
        add(st,i+m*sum,p[i],0),add(i+m*sum,st,0,0);
    for(int i=1;i<=m*sum;i++)
        add(i,en,1,0),add(en,i,0,0);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        add(j+m*sum,(i-1)*sum+1,1,c[j][i]),add((i-1)*sum+1,j+m*sum,0,-c[j][i]);
    max_flow(st,en);
    printf("%d",ansc);
    return 0;
}

 

posted @ 2018-08-29 16:22  logeadd  阅读(228)  评论(0编辑  收藏  举报