【Luogu】P1251餐巾计划(上下界费用流)

  题目链接

  学了一下上下界费用流,似乎很nb。但是我说得不好,所以这里给出博客链接。

  某dalao的博客

  然后这道题的解法就是先用上下界费用流的建图方式连早上和晚上之间的那条边,保证当天一定会有r条或以上的餐巾可用。

  然后考虑买,快洗,慢洗和放起来的诸多情况。

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<queue>
#define maxn 5030
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int from,next,to,val,dis;
}edge[maxn*20];
int head[maxn],num;
inline void addedge(int from,int to,int val,int dis){
    edge[++num]=(Edge){from,head[from],to,val,dis};
    head[from]=num;
}
inline void add(int from,int to,int val,int dis){
    addedge(from,to,val,dis);
    addedge(to,from,0,-dis);
}

inline int count(int i){    return i&1?i+1:i-1;    }

int dis[maxn];
int pre[maxn];
bool vis[maxn];
int flow[maxn];
int Start,End;

int spfa(){
    memset(dis,127/3,sizeof(dis));    int pinf=dis[0];
    dis[Start]=0;    flow[Start]=0x7fffffff;
    queue<int>q; q.push(Start);
    while(!q.empty()){
        int from=q.front();    q.pop();    vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(edge[i].val==0||dis[to]<=dis[from]+edge[i].dis)    continue;
            dis[to]=dis[from]+edge[i].dis;
            pre[to]=i;    flow[to]=min(flow[from],edge[i].val);
            if(vis[to])    continue;
            vis[to]=1;    q.push(to);
        }
    }
    if(dis[End]==pinf)    return 0;
    int now=End;
    while(now!=Start){
        int ret=pre[now];
        edge[ret].val-=flow[End];    edge[count(ret)].val+=flow[End];
        now=edge[ret].from;
    }
    return (long long)dis[End]*flow[End];
}

int r[maxn];

int main(){
    int N=read();    End=N*2+1;
    for(int i=1;i<=N;++i){
        r[i]=read();
        add(Start,i+N,r[i],0);
        add(i,End,r[i],0);
        add(i,i+N,0x7fffffff,0);
    }
    int p=read(),m=read(),f=read(),n=read(),s=read();
    for(int i=1;i<=N;++i){
        add(Start,i,0x7fffffff,p);
        if(i!=N)    add(i,i+1,0x7fffffff,0);
        if(i+m>N)    continue;
        add(i+N,i+m,0x7fffffff,f);
        if(i+n>N)    continue;
        add(i+N,i+n,0x7fffffff,s);
        
    }
    long long ans=0;
    while(1){
        long long now=spfa();
        if(now==0)    break;
        ans+=now;
    }
    printf("%lld\n",ans);
    return 0;
}

 

https://www.luogu.org/problemnew/show/P1251

posted @ 2018-02-14 21:07  Konoset  阅读(117)  评论(0编辑  收藏  举报