zoukankan      html  css  js  c++  java
  • 洛谷1251 餐巾计划问题(网络流24题)

    题目描述

    一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为p分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n天(n>m),其费用为 s分(s<f)。

    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

    试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

    输入格式

    由标准输入提供输入数据。文件第 1 行有 1 个正整数 N,代表要安排餐巾使用计划的天数。

    接下来的 N行是餐厅在相继的N天里,每天需用的餐巾数。

    最后一行包含5个正整数p,m,f,n,s,p是每块新餐巾的费用; m 是快洗部洗一块餐巾需用天数; f 是快洗部洗一块餐巾需要的费用; n是慢洗部洗一块餐巾需用天数; s是慢洗部洗一块餐巾需要的费用。

    输出格式

    将餐厅在相继的 N 天里使用餐巾的最小总花费输出

    题目分析:

      很明显是一道最小费用最大流的题目,问题在于如何建边。对于每天使用的餐巾,很明显需要拆点,分为入出两个点。所以我第一次建边时,每天从源点都建一条流量inf,费用为p的边到该天的入口,入口建一条费用为0,流量为r[i]。这部分是图代表买新纸巾所用花费。后面对于纸巾的回收清洗的建图才是最难的。

      首先,毋庸置疑的是从源点到每天的出点建一条r[i],费用为0的边,表示用过的纸巾数量。

      第一次建图是,我只从出点建了边到i+m和i+n天,后面发现其实不止这两天可以用第i天的纸巾。例如,第一天纸巾需求特别大,洗的又特别快,后面所有天都可以用这天的纸巾,于是,从第i+m,i+n天分别建边到最后一天,表示该天纸巾清洗完之后所有天都可以用,但是如果n和m较小,相当于建了解决$n^{2}$条边,所以就超时了。

      最后看了题解,才明白其实第i天的纸巾虽然可以清洗后在第i+m+b天使用,但可以看做是第i+b天清洗的,所以只需要将每天的出点向下一天出点建一条费用为0,流量为inf(这里不是r[i]因为可能包含前面若干天的纸巾)的边即可,表示这天用的纸巾囤积到后一天去洗,每天都有囤积,可以无限囤积下去。然后第i天往i+m和i+n天分别建流量为inf(注意,这里是inf不是r[i],因为这里前几天的纸巾可能囤积到这里,数量较大),费用为f,s的边即可。

    下面贴上代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <ll,ll> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define de(x) cout<< #x<<" = "<<x<<endl
    #define dd(x) cout<< #x<<" = "<<x<<" "
    #define mes(a,b) memset(a,b,sizeof a)
    const ll inf= 0x3f3f3f3f;
    const ll maxm=5e5,maxn=5005;
    ll n,s,t,x,y,vol,cost,edgecount ; 
    
    pii ans ;
    struct Edge{
        ll to,vol,cost,next ; 
    }edge[2*maxm] ;
    
    ll head[maxn],pre[maxn],path[maxn],dis[maxn] ; 
    void insert(ll u,ll v,ll vol,ll cost) 
    {
    /*    
        dd(u);
        dd(v);
        dd(vol);
        de(cost);
    */    
        edge[edgecount].to = v ; 
        edge[edgecount].vol = vol ; 
        edge[edgecount].cost = cost ;
        edge[edgecount].next = head[u] ; 
        head[u] = edgecount++ ; 
        
        edge[edgecount].to = u ;  
        edge[edgecount].vol = 0 ;
        edge[edgecount].cost = -cost ;
        edge[edgecount].next = head[v] ;   
        head[v] = edgecount++ ;
    }
    bool spfa( ll s,ll t )  
    {
        for(int i=0;i<=n;i++) pre[ i ] = -1 ; 
        for(int i=0;i<=n;i++) dis[ i ] = 1e9 ; 
        dis[ s ] = 0 ; 
        queue<ll> Q ; 
        Q.push(s) ; 
        while(!Q.empty()) 
        {
            ll u = Q.front() ; 
            Q.pop() ; 
            
            for(ll e = head[u];e != -1 ;e = edge[e].next ) 
            {
                ll v = edge[e].to ; 
                if(edge[e].vol>0&&dis[u] + edge[e].cost < dis[v]) 
                {
                    dis[v] = dis[u] + edge[e].cost ; 
                    pre[v] = u ; 
                    path[v] = e ; 
                    Q.push(v) ; 
                }
            }
        }
         if(pre[t]==-1) 
             return false ; 
         return true ; 
    }
    
    pii mincostflow(ll s,ll t) 
    {
        ll cost = 0,flow = 0 ; 
        while(spfa(s,t)) 
        {
            ll f = inf ; 
            for(ll u = t; u != s; u = pre[u] ) 
                if(edge[path[u]].vol < f ) 
                    f = edge[path[u]].vol ;
            flow+=f ; 
            cost+= dis[t] * f ; 
            for(ll u=t;u!=s;u=pre[u] ) 
            {
                edge[path[u]].vol-=f ; 
                edge[path[u]^1].vol+=f ;  
            }
        }
        pii ans ; 
        ans.first = flow ;   ans.second = cost ; 
        return ans ; 
    }
    ll arrcy[2005];
    
    ll haxi(ll day,ll x)
    {
        return n*x+day;
    }
    
    int main() 
    {
    
        ios::sync_with_stdio(false);
    
        cin.tie(0);
        mes(head,-1);
        ll p,d1,c1,d2,c2;
        cin>>n;
        rept(i,1,n) cin>>arrcy[i];
        cin>>p>>d1>>c1>>d2>>c2;
        s=0;
        t=2*n+1;
        rept(i,1,n)
        {
            insert(s,haxi(i,0),inf,p);
    
            insert(haxi(i,0),t,arrcy[i],0);
    
            insert(s,haxi(i,1),arrcy[i],0);
    
            if(i+d1<=n)
                insert(haxi(i,1),haxi(i+d1,0),inf,c1);
    
            if(i+d2<=n)
                insert(haxi(i,1),haxi(i+d2,0),inf,c2);
    
            if(i+1<=n)
                insert(haxi(i,1),haxi(i+1,1),inf,0);
    
        }
        n=2*n+2;
        ans=mincostflow(s,t);
        cout<<ans.se<<"
    ";
        return 0 ; 
    }
  • 相关阅读:
    Javascript Promise对象学习
    JavaScript 判断一个对象的数据类型。
    Angular SEO方案
    【GOF23设计模式】迭代器模式
    【GOF23设计模式】责任链模式
    【GOF23设计模式】享元模式
    【GOF23设计模式】外观模式
    【GOF23设计模式】装饰模式
    【GOF23设计模式】组合模式
    【GOF23设计模式】桥接模式
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/11736869.html
Copyright © 2011-2022 走看看