码迷,mamicode.com
首页 > 其他好文 > 详细

洛谷1251餐巾纸问题

时间:2017-11-30 23:43:13      阅读:421      评论:0      收藏:0      [点我收藏+]

标签:i+1   div   data   学习   org   name   0ms   push   dfs   

题目戳这里

题目描述

一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。

(1)购买新的餐巾,每块需p分;

(2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。

(3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。

在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小

输入输出格式

输入格式:

 

输入文件共3行,第1行为总天数;第2行为每天所需的餐巾块数;第3行为每块餐巾的新购费用p,快洗所需天数m,快洗所需费用f,慢洗所需天数n,慢洗所需费用s。

 

输出格式:

 

输出文件共1行为最小的费用。

 

输入输出样例

输入样例#1: 复制
3
3 2 4
10 1 6 2 3
输出样例#1: 复制
64

说明

N<=2000

ri<=10000000

p,f,s<=10000

时限4s

 

学习了一下zkw费用流,大概就是用dinic跑费用流,,快的飞起  

  建图还很麻烦。把每天拆成ai,bi两点,ai表示用过的,bi没用过。建立超级源汇S,T。

  (1)S向ai连容量r[i],费用0的边,S向bi连容量r[i],费用p的边

  (2)bi向T连容量r[i],费用0的边

  (3)ai向b(i+m)连容量无穷,费用f的边,ai向b(i+n)连容量无穷,费用f的边,ai向a(i+1)连容量无穷费用0的边

  然后zkw 50ms过了

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define N 2005
using namespace std;
int day,n,m,p,s,f,S,T,tot,r[N],cur[N<<1],hd[N<<1],vis[N<<1],d[N<<1]; 
ll cost;
struct edge{int u,v,w,next,cap,flow;}e[N<<4];
void adde(int u,int v,int w,int c){
    e[tot].u=u;
    e[tot].v=v;
    e[tot].w=w;
    e[tot].cap=c;
    e[tot].next=hd[u];
    hd[u]=tot++;
}

bool spfa(){
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    deque<int>q;d[T]=0;q.push_back(T);
    while(!q.empty()){
        int u=q.front();q.pop_front();vis[u]=0;
        for(int i=hd[u];~i;i=e[i].next){
            if(e[i^1].cap<=e[i^1].flow)continue;
            int w=e[i^1].w,v=e[i].v;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                if(vis[v])continue;
                vis[v]=1;
                if(!q.empty()&&d[v]<d[q.front()])q.push_front(v);
                else q.push_back(v);
            }
        }
    }
    return d[S]<0x3f3f3f3f;
}

int dfs(int u,int a){
    if(!a||u==T)return a;
    vis[u]=1;int f=0,fl=0;
    for(int &i=cur[u];~i;i=e[i].next){
        int v=e[i].v;
        if(d[v]+e[i].w==d[u]&&!vis[v]&&(f=dfs(v,min(e[i].cap-e[i].flow,a)))){
            cost+=(ll)f*e[i].w;fl+=f;
            e[i].flow+=f;
            e[i^1].flow-=f;
            a-=f;
            if(!a)break;
        }
    }
    vis[u]=0;return fl;
}

int main(){
#ifdef wsy
    freopen("data.in","r",stdin);
#else
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
#endif
    memset(hd,-1,sizeof(hd));
    scanf("%d",&day);S=0;T=(day<<1)+1;
    for(int i=1;i<=day;i++)scanf("%d",&r[i]);
    scanf("%d%d%d%d%d",&p,&m,&f,&n,&s);
    for(register int i=1;i<=day;i++){
        adde(S,i,0,r[i]);adde(i,S,0,0);
        adde(S,i+day,p,inf);adde(i+day,S,-p,0);
        if(i!=day)adde(i,i+1,0,inf),adde(i+1,i,0,0);
        adde(i+day,T,0,r[i]);adde(T,i+day,0,0);
        if(i+m<=day)adde(i,i+day+m,f,inf),adde(i+day+m,i,-f,0);
        if(i+n<=day)adde(i,i+day+n,s,inf),adde(i+day+n,i,-s,0);
    }
    while(spfa()){
        for(int i=S;i<=T;i++)cur[i]=hd[i];
        dfs(S,inf);
    }
    printf("%lld",cost);
    return 0;
}

  

洛谷1251餐巾纸问题

标签:i+1   div   data   学习   org   name   0ms   push   dfs   

原文地址:http://www.cnblogs.com/wsy01/p/7932123.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!