参考题解:http://blog.csdn.net/yxuanwkeith/article/details/52254602

//开始跑费用流用的dijkstra,一直错,后来发现动态加边后我不会处理势函数;
//因为加进一些边后1号点到某个点的最短路不好更新,有些点是有势函数的,有些没有,图不平衡了;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
int head,tail,q[maxn],H[maxn],last[maxn],inf,All,S,T,n,m,Min,t[50][1000],vis[maxn],dis[maxn],in[maxn],p[50],cnt;
struct edg{
    int nxt,to,f,c;
}e[maxn*2];
void insert(int x,int y,int z,int zz){
    ++cnt;e[cnt].nxt=last[x];last[x]=cnt;e[cnt].to=y;e[cnt].f=z;e[cnt].c=zz;
}
void add(int x,int k){
    //加第x个厨师的第k组边
    int u=(x-1)*All+k;
    if(k>All||vis[u])return;
    vis[u]=1;
    insert(S,u,1,0);insert(u,S,0,0);
    for(int i=1;i<=n;++i)
    {insert(u,All*m+i,1,t[i][x]*k);insert(All*m+i,u,0,-t[i][x]*k);}
}
int dfs(int x,int h){
    if(x==T){Min+=dis[T]*h;return h;}
    int tmp=0,cp;in[x]=1;
    for(int i=last[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(dis[v]==dis[x]+e[i].c&&e[i].f&&!in[v]){
            cp=dfs(v,min(h-tmp,e[i].f));
            e[i].f-=cp;e[i^1].f+=cp;tmp+=cp;
            if(tmp==h){//动态加边:当前点跑满流了就新加边;
                //注意加边的顺序,先加费用小的;
                if(x<=All*m&&x!=S)add((x-1)/All+1,(x-1)%All+2);
                return tmp;
            }
        }
    }
    return tmp;
}
void solve(){
    while(1){
        memset(in,0,sizeof(in));memset(dis,60,sizeof(dis));
        inf=dis[0];dis[S]=0;head=tail=0;
        q[++tail]=S;
        while(head!=tail){
            head=(head+1)%maxn;
            int u=q[head];
            for(int i=last[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(e[i].f&&dis[v]>dis[u]+e[i].c){
                    dis[v]=dis[u]+e[i].c;
                    if(!in[v]){
                        in[v]=1;tail=(tail+1)%maxn;
                        q[tail]=v;
                    }
                }
            }
            in[u]=0;
        }
        if(dis[T]==inf)return;
        dfs(S,inf);
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        scanf("%d",&p[i]);All+=p[i];
    }
    S=0,T=m*All+n+1;
    cnt=1;
    for(int i=1;i<=n;++i){
        insert(All*m+i,T,p[i],0);
        insert(T,All*m+i,0,0);
        for(int j=1;j<=m;++j)scanf("%d",&t[i][j]);
    }
    for(int i=1;i<=m;++i)add(i,1);
    solve();
    cout<<Min;
    system("pause");
    return 0;
}

 

posted on 2018-01-11 20:58  湮灭之瞳  阅读(146)  评论(0编辑  收藏  举报