zoukankan      html  css  js  c++  java
  • Luogu P1251 餐巾计划问题

    不得不说这是一道非常好的费用流神题。

    建图清新自然,构建没有毒瘤。实为网络流24题中难得一见的好题。

    我们考虑一下网络流的建图

    首先拆点并建立超级源点SS和超级汇点(T)(常见套路),我们把每一天拆成早上(x_i)晚上(y_i)

    然后考虑每天早上要向(T)提供(r_i)条干净的餐巾,而(S)要向每天晚上提供(r_i)条脏餐巾。

    然后就是一些购买和洗的问题了,这个我们就来细致地讲一讲建边(这里边带费用)

    1. 同上,从(x_i)(T)连一条流量为(r_i),费用为(0)(又没买餐巾怎么要钱?)的边。
    2. 同上,从(S)(y_i)连一条流量为(r_i),费用为(0)的边。
    3. 考虑每天早上购买餐巾,我们从(S)(x_i)连一条流量为(infty),费用为(p)的边。
    4. 然后是快洗,我们从(y_i)(x_{i+m})连一条流量为(infty),费用为(f)的边。表示可以在第(i)天晚上送一些餐巾去洗。需要注意的是(i+mle n)
    5. 慢洗同上,我们从(y_i)(x_{i+n})连一条流量为(infty),费用为(s)的边。
    6. 然后有一个大坑点来了:每天晚上脏的餐巾不一定一定要去洗,也可以攒到第二天再洗或者直接不管了。因此我们从所有的(y_i(1le i<n))(y_{i+1})连一条流量为(infty),费用为(0)的边。注意这里必须由晚上连至晚上,因为脏餐巾不能在早上使用

    然后我们都要建反向边。然后直接跑EK+SPFA是可以直接过的。但注意开long long

    CODE

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long LL;
    const LL N=4005,INF=1e18;
    queue <LL> q;
    struct edge
    {
        LL to,next,c,f;
    }e[N<<3];
    LL head[N],dis[N],cap[N],pre[N],last[N],s,t,n,x,y,cnt=-1;
    bool vis[N];
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(LL &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline void add(LL x,LL y,LL c,LL f)
    {
        e[++cnt].to=y; e[cnt].c=c; e[cnt].f=f; e[cnt].next=head[x]; head[x]=cnt;
    }
    inline void insert(LL x,LL y,LL c,LL f)
    {
        add(x,y,c,f); add(y,x,0,-f);
    }
    inline LL min(LL a,LL b)
    {
        return a<b?a:b;
    }
    inline bool SPFA(void)
    {
        memset(dis,63,sizeof(dis));
        memset(cap,63,sizeof(cap));
        memset(pre,-1,sizeof(pre));
        memset(vis,0,sizeof(vis));
        while (!q.empty()) q.pop();
        q.push(s); vis[s]=1; dis[s]=0;
        while (!q.empty())
        {
            LL now=q.front(); q.pop(); vis[now]=0;
            for (register LL i=head[now];i!=-1;i=e[i].next)
            if (e[i].c&&dis[e[i].to]>dis[now]+e[i].f)
            {
                dis[e[i].to]=dis[now]+e[i].f;
                cap[e[i].to]=min(cap[now],e[i].c);
                pre[e[i].to]=now; last[e[i].to]=i;
                if (!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
            }
        }
        return pre[t]^-1;
    }
    inline void MCMF(void)
    {
        LL tot=0;
        while (SPFA())
        {
            tot+=cap[t]*dis[t]; LL now=t;
            while (now!=s)
            {
                e[last[now]].c-=cap[t];
                e[last[now]^1].c+=cap[t];
                now=pre[now];
            }
        }
        printf("%lld",tot);
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register LL i; read(n); s=0; t=(n<<1)+1;
        memset(head,-1,sizeof(head));
        memset(e,-1,sizeof(e));
        for (i=1;i<=n;++i)
        read(x),insert(s,i+n,x,0),insert(i,t,x,0);
        for (read(x),i=1;i<=n;++i)
        {
            insert(s,i,INF,x);
            if (i^n) insert(i+n,i+n+1,INF,0);
        }
        for (read(x),read(y),i=1;i+x<=n;++i)
        insert(i+n,i+x,INF,y);
        for (read(x),read(y),i=1;i+x<=n;++i)
        insert(i+n,i+x,INF,y);
        MCMF(); return 0;
    }
    
  • 相关阅读:
    OGRE 第一个程序
    C++ 模板
    WTL状态栏出现 'CMultiPaneStatusBarCtrl' : missing storageclass or type specifie错误
    OGRE运行期结构
    WTL头文件中包含的类
    WTL 方式 对话框数据交换(DDX)
    Windows编程--线程的基本知识
    OGRE——OgreMain模块
    php函数call_user_func和call_user_func_array详解
    整合ECShop2.7.2与Discuz!6.0
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9188003.html
Copyright © 2011-2022 走看看