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

建边有技巧啊,要拆点。
网络流建边的核心规律就是多做题一定是从源点到汇点,根据此构建模型即可。
\(dinic\) 实现最小费用流

/*
@Date    : 2019-07-16 11:10:42
@Author  : Adscn (adscn@qq.com)
@Link    : https://www.cnblogs.com/LLCSBlog
*/
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
IL int getint()
{
    RG int xi=0;
    RG char ch=gc;
    bool f=0;
    while(ch<'0'|ch>'9')ch=='-'?f=1:f,ch=gc;
    while(ch>='0'&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
    return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
    if(k<0)k=-k,putchar('-');
    if(k>=10)pi(k/10,0);
    putchar(k%10+'0');
    if(ch)putchar(ch);
}
const int inf=2147483647,N=2007;
int S=0,T;
struct edge{int v,nxt,flow,w;}e[N<<2];
int head[N<<1],cnt;
int cur[N<<1];
inline void add(int u,int v,int flow,int cost){e[cnt]=(edge){v,head[u],flow,cost};head[u]=cnt++;}
inline void link(int u,int v,int flow,int cost){add(u,v,flow,cost);add(v,u,0,-cost);}
int dis[N<<1];
bool vis[N<<1];
int spfa()
{
    memset(dis,127,sizeof dis);
    memset(vis,0,sizeof vis);
    static int Q[N<<1],l,r;
    dis[Q[l=r=0]=S]=0;
    while(l<=r)
    {
        int p=Q[l++];
        vis[p]=0;
        for(int i=head[p];~i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(dis[v]>dis[p]+e[i].w&&e[i].flow)
            {
                dis[v]=dis[p]+e[i].w;
                if(!vis[v])Q[++r]=v,vis[v]=1;
            }
        }
    }
    return dis[T]<1e9;
}
long long ans;
int dfs(int p,int restflow)
{
    if(p==T||restflow==0)return restflow;
    int sumflow=0;
    vis[p]=1;
    for(int &i=cur[p],flow;(~i)&&restflow;i=e[i].nxt)
    {
        int v=e[i].v;
        if(vis[v]==0&&e[i].flow&&dis[v]==dis[p]+e[i].w&&(flow=dfs(v,min(restflow,e[i].flow))))
        {
            sumflow+=flow,restflow-=flow;
            e[i].flow-=flow,e[i^1].flow+=flow;
            ans+=1ll*flow*e[i].w;
        }
    }
    vis[p]=0;
    return sumflow;
}
void dinic(){while(spfa())memcpy(cur,head,sizeof head),dfs(S,inf);}
int main(void)
{
    #ifndef ONLINE_JUDGE
    File("file");
    #endif
    int n=gi;T=n*2+1;
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;++i)
    {
        int x=gi;
        link(S,i,x,0);
        link(i+n,T,x,0);
    }
    int newcost=gi,fastday=gi,fastcost=gi,slowday=gi,slowcost=gi;
    for(int i=1;i<=n;++i)
    {
        if(i<n)link(i,i+1,inf,0);
        if(i+slowday<=n)link(i,i+n+slowday,inf,slowcost);
        if(i+fastday<=n)link(i,i+n+fastday,inf,fastcost);
        link(S,i+n,inf,newcost);
    }
    dinic();
    pi(ans);
    return 0;
}

转载于:https://www.cnblogs.com/LLCSBlog/p/11195381.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值