网络流24题 餐巾计划问题 解题报告

餐巾计划问题

这建图太厉害了,我想了巨久都没想到怎么控制流量先合法又能流到别的地方去。

还是思维太烂了qaq

用了一个把流量拆开的思路,就叫Ta拆流吧

具体的说,我们对一个点,有一个流量一定要流,但是这个流量也可以给后面的用,我们就把这个流拆开。

对应此题,先把点拆成\(i\)\(i+n\),然后\(i\)连接\(t\)表示流量限制,费用为\(0\),要流满,这也是整个图唯一连接\(t\)的边。

然后\(i+n\)表示当天用完的这个脏餐巾的流,这个流可以给下一天的脏餐巾,可以送去快洗慢洗再给对应的\(j\)号点代表\(j\)得到流

然后建一下买餐巾的流就可以了


Code:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <queue>
#include <algorithm>
using std::min;
#define ll long long
template <class T>
void read(T &x)
{
    x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=4010;
const int M=1e5;
const int inf=0x3f3f3f3f;;
int head[N],to[M],Next[M],edge[M],cost[M],cnt=1;
void add(int u,int v,int w,int c)
{
    to[++cnt]=v,edge[cnt]=w,cost[cnt]=c,Next[cnt]=head[u],head[u]=cnt;
    to[++cnt]=u,edge[cnt]=0,cost[cnt]=-c,Next[cnt]=head[v],head[v]=cnt;
}
int n,need[N],s,t;
int used[N],dis[N],pre[N];
bool spfa()
{
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    std::queue <int> q;
    q.push(s);
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        used[now]=0;
        for(int v,i=head[now];i;i=Next[i])
            if(edge[i]&&dis[v=to[i]]>dis[now]+cost[i])
            {
                dis[v]=dis[now]+cost[i];
                pre[v]=i;
                if(!used[v]) q.push(v),used[v]=1;
            }
    }
    return dis[t]<dis[0];
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(need[i]);
    int t1,t2,p0,p1,p2;
    read(p0),read(t1),read(p1),read(t2),read(p2);
    s=n<<1|1,t=s+1;
    for(int i=1;i<=n;i++)
    {
        add(s,i,inf,p0);
        add(i,t,need[i],0);
        add(s,i+n,need[i],0);
        if(i<n) add(i+n,i+1+n,inf,0);
        if(i+t1<=n) add(i+n,i+t1,inf,p1);
        if(i+t2<=n) add(i+n,i+t2,inf,p2);
    }
    ll ans=0;
    while(spfa())
    {
        int mi=inf,now=t;
        while(pre[now])
        {
            mi=min(mi,edge[pre[now]]);
            now=to[pre[now]^1];
        }
        ans+=mi*dis[t];now=t;
        while(pre[now])
        {
            edge[pre[now]]-=mi;
            edge[pre[now]^1]+=mi;
            now=to[pre[now]^1];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

2019.2.26

猜你喜欢

转载自www.cnblogs.com/butterflydew/p/10438141.html