博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

洛谷 P1251 餐巾计划问题 解题报告

网络流24题练习。

一开始看到题目,觉得挺简单。

然后在如何处理 " 一天用完的脏毛巾洗完后转移到后面的天数 " 时卡住了。


 

思路是这样的:

  1. 将每一天拆成早晚两个点,分开处理脏/新毛巾。(用i表示早上,i+n表示晚上,ai表示每天需要的毛巾)
  2. s -> i+n连容量为ai的边,表示这一天晚上得到了ai条脏毛巾
  3. i -> t 连容量为ai的边,表示每天早上提供ai条新毛巾
  4. i+n -> i+n+1,容量inf,表示脏毛巾留到了下一天晚上
  5. i+n -> i+d1,容量inf,费用c1,表示脏毛巾送到快洗店,第i+d1天早上洗好了。
  6. i+n -> i+d2,容量inf,费用c2,表示脏毛巾送到慢洗店,第i+d2天早上洗好了。
  7. s -> i ,容量inf,费用=买新毛巾的费用,表示每一天可以买新毛巾

建完图dinic走一波。注意开long long。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define space putchar(' ')
#define endl putchar('\n')
#define debug puts("------------------------")
#define F(i,x,n) for(int i=x;i<=n;++i)
#define F_(i,x,n) for(int i=x;i>=n;--i)
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
inline int  Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; }
inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);}
inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);}
/**/
const int N=4005,inf=0x3f3f3f3f;
const ll INF=(ll)(0x3f3f3f3f3f3f3f3f);
int n,s,t,x,head[N],cur[N],cnt=1;
ll dis[N],mincost;
int buy,c1,d1,c2,d2;
bool vis[N];
struct edge
{
    int nxt,to,c,w;
}e[N*100];
/**/
namespace DINIC
{
    inline int get(int i,int j,int p=0)
    {
        return (i-1)*n + j + n*n*p;
    }
    inline void addone(int u,int v,int c,int w)
    {
        e[++cnt]=(edge){head[u],v,c,w};
        head[u]=cnt;
    }
    inline void add(int u,int v,int c,int w)
    {
        addone(u,v,c,w);
        addone(v,u,0,-w);
    }
    inline int bfs()
    {
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        memcpy(cur,head,sizeof(head));
        vis[s]=1,dis[s]=0;
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();vis[u]=0;
            for(int i=head[u];i;i=e[i].nxt)
            {
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].w&&e[i].c)
                {
                    dis[v]=dis[u]+e[i].w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return dis[t]!=INF;
    }
    int dfs(int u,int flow)
    {
        if(u==t)
        {
            vis[t]=1;
            return flow;
        }
        vis[u]=1;
        int used=0,minflow=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if((!vis[v]||v==t)&&dis[v]==dis[u]+e[i].w&&e[i].c)
            {
                if((minflow=dfs(v,min(flow-used,e[i].c)))!=0)
                {
                    used+=minflow;
                    e[i].c-=minflow;
                    e[i^1].c+=minflow;
                    mincost+=e[i].w*minflow;
                    if(used==flow) break;
                }
            }
        }
        return used;
    }
    ll Dinic()
    {
        while(bfs())
        {
            vis[t]=1;
            while(vis[t])
            {
                memset(vis,0,sizeof(vis));
                dfs(s,inf);
            }
        }
        return mincost;
    }
}using namespace DINIC;
int main()
{
    read(n);s=n+n+1,t=s+1;
    for(int i=1,x;i<=n;i++)
    {
        read(x);
        add(s,i+n,x,0);
        add(i,t,x,0);
    }
    read(buy);read(d1);read(c1);read(d2);read(c2);
    for(int i=1;i<=n;i++)
    {
        add(i+n,i+n+1,inf,0);
        if(i+d1<=n) add(i+n,i+d1,inf,c1);
        if(i+d2<=n) add(i+n,i+d2,inf,c2);
        add(s,i,inf,buy);
    }
    cout<<Dinic();
}
View Code

 

  

     

 

posted @ 2019-03-18 11:00  楚泫  阅读(140)  评论(0编辑  收藏  举报