zoukankan      html  css  js  c++  java
  • bzoj2879[NOI2012]美食节

    传送门

    最小费用最大流,这个题是修车的加强版,暴力建图是60分,所以这个题需要动态加边,动态加边的思路很显然,最先只把厨师做第一道菜加边,之后每做完一道菜再加(n)条边就好啦,此题有及其恶(稀)心(疏)的图,zkw费用流会被卡成80分,所以只能写EK

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    inline void read(int &x) {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define min(a,b) (a<b?a:b)
    #define rg register
    queue<int>q;int n,m,s,t,num,b[2000001],c[2000001],a[41][101],g[41],pre[2000001],dis[100010],nxt[2000001],h[100010],v[2000001],w[2000001],cnt=1,inf=1e9,ans,que[2000001];bool vis[100010];
    inline void add(int x,int y,int z,int u)
    {
        pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z,w[cnt]=u,
        pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=0,w[cnt]=-u;
    }
    bool spfa(int s)
    {
        memset(dis,63,sizeof dis);
        q.push(s),dis[s]=0;
        while(!q.empty())
        {
            int x=q.front();q.pop(),vis[x]=0;
            for(rg int i=h[x];i;i=nxt[i])
                if(v[i]&&dis[pre[i]]>dis[x]+w[i])
                {
                    dis[pre[i]]=dis[x]+w[i],b[pre[i]]=x,c[pre[i]]=i;
                    if(!vis[pre[i]])vis[pre[i]]=1,q.push(pre[i]);
                }
        }
        return dis[t]<inf;
    }
    int getans()
    {
        int mn=inf,x;
        for(rg int i=t;i!=s;i=b[i])mn=min(v[c[i]],mn);
        for(rg int i=t;i!=s;i=b[i])v[c[i]]-=mn,v[c[i]^1]+=mn;
        x=b[t];for(rg int i=1;i<=n;i++)add(i,x+1,1,a[i][x/num]*(que[x+1]=que[x]+1));
        return dis[t]*mn;
    }
    int main()
    {
        read(n),read(m);
        for(rg int i=1;i<=n;i++)read(g[i]),num+=g[i];
        s=0,t=num*(m+1)+1;
        for(rg int i=1;i<=n;i++)
        	for(rg int j=1;j<=m;j++)
        		read(a[i][j]);
        for(rg int i=1;i<=n;i++)
        	for(rg int j=1;j<=m;j++)
        		add(i,j*num+1,1,a[i][j]),que[j*num+1]=1;
        for(rg int i=1;i<=n;i++)add(s,i,g[i],0);
        for(rg int i=1;i<=num;i++)for(rg int j=1;j<=m;j++)add(j*num+i,t,1,0);
        while(spfa(s))ans+=getans();
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    新入行程序员考虑自己是否明白以下这8件事情
    程序猿品种总结你是哪一类?
    利用趣味漫画讲述云计算起源
    设计师遇到瓶颈时的五个解困惑建议
    可以帮助到我今后的程序员生涯的十分钟思考
    oc编程中继承的相关实例
    centos和ubuntu服务器Bash漏洞修复方法
    jQuery经典面试题精选
    phpstudy -sql服务器2008r2 -中控考勤机 -php 组合查询考勤
    bat 批处理测试局域网速度 两端电脑
  • 原文地址:https://www.cnblogs.com/lcxer/p/10223456.html
Copyright © 2011-2022 走看看