【网络流24题10】餐巾计划问题

题面传送机

Sol

最小费用最大流
建图方式真麻烦 真是网络流里的泥石流清流啊
老规矩 先建立超源点S和超汇点E
对于每一天 , 我们可以拆成2个点 , 一个点称为1号连接S , 另外一个称为2号连接E , 流量都是当天餐巾 , 费用0
由于我们可以不洗餐巾所以可以直接连接下一天 (俩一号点连接), 费用为0 , 流量INF(注意边界)
我们可以买餐巾所以可以直接买直接S连向2号点 流量为INF 费用为价格
还可以洗餐布 , 把每天与洗完之后(i + n + day)的那一天的二号点相连 费用为洗餐布费用 流量INF(注意边界)

Code

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstring>
typedef int trueint;
#define int long long
#define inc(i) (i = -(~i))
#define dec(i) (i = ~(-i))
using namespace std;

namespace fast
{
    inline char Getchar()
    {
        static char buf[1000001] , *p1 = buf , *p2 = buf;
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 1000000 , stdin) , p1 == p2) ? EOF : *p1 ++;
    }
    inline int read()
    {
        int num = 0; char c = 0;
        while(!isdigit(c)) c = Getchar();
        while(isdigit(c)) num = num * 10 + c - '0' , c = Getchar();
        return num;
    }
}
using namespace fast;

const int N = 20000 + 7 , M = 2000000 + 7 , INF = 0x3f3f3f3f;
int n , Fast_Wash_Cost , Fast_Wash_Day , Slow_Wash_Cost , Slow_Wash_Day , Everyday[N] , Buy;//in
int Head[N] , Node[M] , W[M] , Next[M] , tot = 1 , S , E , Co[M];//Map
int Min_Cost , Dep[N];//Others

inline void Add(int u , int v , int Flow , int Cost)
{
    Next[inc(tot)] = Head[u] , Head[u] = tot , W[tot] = Flow , Node[tot] = v , Co[tot] = Cost;
    Next[inc(tot)] = Head[v] , Head[v] = tot , W[tot] = 0 , Node[tot] = u , Co[tot] = -Cost;
}

inline void Build_Map()
{
    for(int i = 1 ; i <= n ; inc(i))
    {
        Add(S , i , Everyday[i] , 0);//拆点1号连起点
        Add(i + n , E , Everyday[i] , 0);//拆点2号连终点
        Add(S , i + n , INF , Buy);//买新的
        if(i < n)   Add(i , i + 1 , INF , 0);
        if(i + Fast_Wash_Day <= n)   Add(i , i + Fast_Wash_Day + n , INF , Fast_Wash_Cost);
        if(i + Slow_Wash_Day <= n)   Add(i , i + Slow_Wash_Day + n , INF , Slow_Wash_Cost);
    }
}

struct Queue
{
    int Que[N] , l , r;
    inline void cls() {l = 100 , r = 99;}
    inline int top() {return Que[l];}
    inline void push(int x) {Que[inc(r)] = x;}
    inline bool full() {return r >= l;}
    inline void pop() {inc(l);}
}Q;

bool inq[N] , book[N];
inline bool SPFA()
{
    memset(inq , 0 , sizeof(inq));
    memset(Dep , 0x3f3f3f3f , sizeof(Dep));
    int Big = Dep[1] , u , v;
    Q.cls() , Dep[S] = 0 , Q.push(S);
    while(Q.full())
    {
        u = Q.top() , Q.pop() , inq[u] = 0;
        for(int i = Head[u] ; i ; i = Next[i])
        {
            v = Node[i];
            if(Dep[v] > Dep[u] + Co[i] && W[i])
            {
                Dep[v] = Dep[u] + Co[i];
                if(!inq[v])
                {
                    inq[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
  // printf("Dep[E] = %lld\n" , Dep[E]);
    return Dep[E] != Big;
}

inline int DFS(int u , int lastc)
{
    if(u == E) return lastc;
    int Now = 0 , v , Flow;
    book[u] = 1;
    for(int i = Head[u] ; i ; i = Next[i])
    {
        v = Node[i];
        if(W[i] && !book[v] && Dep[u] == Dep[v] - Co[i])
        {
            Flow = DFS(v , min(lastc - Now , W[i]));
            if(Flow)
            {
                W[i] -= Flow;
                W[i ^ 1] += Flow;
                Now += Flow;
                Min_Cost += Flow * Co[i];
                if(Now == lastc)    break;
            }
        }
    }
   // printf("Now = %lld\n" , Now);
    return Now;
}

inline void Max_Flow()
{
    int Flow;
    while(SPFA())
    {
        // printf("RE1");
        while(1)
        {
            // printf("RE2");
            memset(book , 0 , sizeof(book));
            Flow = DFS(S , INF);
            if(!Flow)   break;
        }
    }
}

trueint main()
{
    n = read();
    for(int i = 1 ; i <= n ; inc(i))    Everyday[i] = read();
    S = n + n + n + 2 , E = S + 2;
    Buy = read() , Fast_Wash_Day = read() , Fast_Wash_Cost = read() , Slow_Wash_Day = read() , Slow_Wash_Cost = read();
    Build_Map();
    Max_Flow();
    printf("%lld" , Min_Cost);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章