【网络流24题】餐巾计划(最小费用流)

来源:互联网 发布:金庸群侠传 for mac 编辑:程序博客网 时间:2024/05/17 23:44

传送门

    餐巾计划

I think

    最小费用最大流。增设源汇点S,T,每i天分两个点xi,yi,分别表示每天应有餐巾与最终解决的餐巾数。记(x,y,u,v)表示x连向y点容量为u费用为v点的边,连接以下边(S,xi,ai,0),(yi,T,ai,0),(xi,xi+1,Inf,0),(xi,yi+qk,Inf,qc),(xi,yi+lk,Inf,lc);最后用SPFA+增广路思想求出最小费用即可。
    另算法函数名很无赖地用了SPFA。

Code

#include<cstdio>#include<queue>using namespace std;const int sm = 2200;const int sn = 12200;const int Inf = 0x3f3f3f3f;int N,nw,qk,qc,lw,lc,Ans,tot=1,S,T;int to[sn],nxt[sn],hd[sm],c[sn],f[sn];int pre[sm],vis[sm],cst[sm];int Min(int x,int y) { return x<y?x:y; }void Add(int u,int v,int w,int val) {    to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=w,f[tot]=val;    to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0,f[tot]=-val;}void SPFA() {    int t,df; queue<int>q;    while(1) {        for(int i=1;i<=T;++i)             pre[i]=vis[i]=0,cst[i]=Inf;        cst[S]=0,vis[S]=1,q.push(S);        while(!q.empty()) {            t=q.front(),q.pop();            vis[t]=0;            for(int i=hd[t];i;i=nxt[i])                if(cst[to[i]]>cst[t]+f[i]&&c[i]>0) {                    cst[to[i]]=cst[t]+f[i];                    pre[to[i]]=i;                    if(!vis[to[i]]) {                        vis[to[i]]=1;                        q.push(to[i]);                    }                }        }        if(cst[T]==Inf)break;        df=Inf;        for(int i=T;i!=S;i=to[pre[i]^1])             df=Min(df,c[pre[i]]);        for(int i=T;i!=S;i=to[pre[i]^1])             c[pre[i]]-=df,c[pre[i]^1]+=df;        Ans+=df*cst[T];    }    printf("%d\n",Ans); }int main() {    int u;    scanf("%d%d%d%d%d%d",&N,&nw,&qk,&qc,&lw,&lc);    S=N<<1|1,T=S+1;    for(int i=1;i<=N;++i) {        scanf("%d",&u);        Add(S,i,u,0),Add(i+N,T,u,0);        Add(S,i+N,Inf,nw);        if(i+1<=N) Add(i,i+1,Inf,0);        if(i+qk<=N) Add(i,i+N+qk,Inf,qc);        if(i+lw<=N) Add(i,i+N+lw,Inf,lc);    }    SPFA();    return 0;}
阅读全文
0 0
原创粉丝点击