洛谷 P1251 餐巾计划问题

题目链接

最小费用最大流。

每天拆成两个点,早上和晚上;

晚上可以获得\(r_i\)条脏毛巾,从源点连一条容量为\(r_i\),费用为0的边。

早上要供应\(r_i\)条毛巾,连向汇点一条容量为\(r_i\)吗,费用为0的边。

每天可以买毛巾,晚上向第二天早上连一条费用为\(p\),容量为\(inf\)的边。

可以送快洗,晚上向\(m\)天之后的早上连费用\(f\),容量\(inf\)的边

可以送慢洗,晚上向\(n\)天之后的早上连费用\(s\),容量\(inf\)的边

脏毛巾可以留到第二天晚上,源点向第二天晚上连一条容量\(r_i\),费用0的边。

最后跑费用流即可。

常数巨大的代码

#include<bits/stdc++.h>
using namespace std;
 
#define int long long 
 
inline void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
}
 
inline void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar((x%10)^48);
}
inline void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
 
#define maxn 1000050

int n,m,s,t,max_flow,tot=1,min_cost;
int head[maxn],dis[maxn],vis[maxn],v[70][70];
struct edge{int to,nxt,w,c;}e[maxn<<1];

void add(int u,int v,int w,int c) {e[++tot]=(edge){v,head[u],w,c},head[u]=tot;}
void ins(int u,int v,int w,int c) {add(u,v,w,c),add(v,u,0,-c);}

int spfa() {
    memset(vis,0,sizeof vis);
    memset(dis,63,sizeof dis);
    queue<int > q;q.push(s);dis[s]=0;vis[s]=1;
    while(!q.empty()) {
        int now=q.front();q.pop();vis[now]=0;
        for(int i=head[now];i;i=e[i].nxt)
            if(e[i].w>0&&dis[e[i].to]>dis[now]+e[i].c) {
                dis[e[i].to]=dis[now]+e[i].c;
                if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
            }
    }return dis[t]<1e9;
}

int dfs(int u,int f) {
    if(u==t) {max_flow+=f,min_cost+=f*dis[t],vis[t]=1;return f;}
    vis[u]=1;int used=0;
    for(int i=head[u];i;i=e[i].nxt)
        if(e[i].w>0&&dis[e[i].to]==dis[u]+e[i].c&&!vis[e[i].to]) {
            int flow=dfs(e[i].to,min(f-used,e[i].w));
            if(flow>0) {e[i].w-=flow,e[i^1].w+=flow;return flow;}
            if(used==f) break;
        }
    return used;
}

void cost_flow() {
    while(spfa()) {
        vis[t]=1;
        while(vis[t]) memset(vis,0,sizeof vis),dfs(s,1e9);
    }
}

signed main() {
    read(n);int x;s=0,t=n*2+1;
    for(int i=1;i<=n;i++) read(x),ins(s,i,x,0),ins(i+n,t,x,0);
    int p,m,f,nn,ss;read(p),read(m),read(f),read(nn),read(ss);
    for(int i=1;i<=n;i++) {
        ins(s,i+n,1e7,p);
        if(i+m<=n) ins(i,i+m+n,1e7,f);
        if(i+nn<=n) ins(i,i+nn+n,1e7,ss);
        if(i+1<=n) ins(i,i+1,1e7,0);
    }cost_flow();write(min_cost);
    return 0;
}

posted @ 2018-11-07 12:06  Hyscere  阅读(117)  评论(0编辑  收藏  举报