[联合集训6-19] 新干线 猜测题意+拆点网络流

题意还有一些细节如下:
1. 同一站点同一轨道同一时刻最多只能发一列货车
2. 直接经过的列车不占用停车位
3. 每条轨道上不允许发生客车超过货车的情况,但同时出发或同时到达某站是合法的,而且不占用该站台的停车位,就算客车货车速度相同且同时出发仍然算合法的
4. 求能发出货车且在 Maxtime M a x t i m e 内到达终点的最大值。

题中说到不能影响客车运行,也就是每列客车中途不停,到每个站的时间(同样也是从该站发车的时间)都是确定的。假设有一列客车在时刻 t t i站出发,那么可以转化成一条限制,即 [tQi+Si,t1] [ t − Q i + S i , t − 1 ] 这段时间内占用一条轨道(这段时间内不能向该轨道发货车),于是我们可以预处理出 fi,t f i , t 表示站 i i 在时间t可用的轨道数。于是我们把每个站拆成 Maxtime M a x t i m e 个点,对于 (i,t) ( i , t ) (i,t+1) ( i , t + 1 ) 连容量为 Pi P i 的边, (i,t) ( i , t ) (i+1,t+Si) ( i + 1 , t + S i ) 连容量为 fi,t f i , t 的边,跑最大流就是答案。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define G(x,t) ((x)*(mxt+1)+(t)) 
#define N 60
#define M 210
using namespace std;
const int mxt=200;
const int inf=0x3f3f3f3f;
int tote,n,P[N],T[N],Q[N],S[N],fre[N][M],ans,con[N*M],nxt[N*M<<2],to[N*M<<2],f[N*M<<2],c[N*M<<2],ne[N*M],dl[N*M],ss,tt;
void ins(int x,int y,int cc)
{
    to[++tote]=y;c[tote]=cc;nxt[tote]=con[x];con[x]=tote;
    to[++tote]=x;c[tote]=0;nxt[tote]=con[y];con[y]=tote;
}
bool bfs()
{
    memset(ne,0,sizeof(ne));
    ne[ss]=1;dl[1]=ss;
    for(int hd=1,tl=1,v=ss;hd<=tl;v=dl[++hd])
        for(int p=con[v];p;p=nxt[p])
            if(c[p]>f[p]&&!ne[to[p]])
                ne[to[p]]=ne[v]+1,dl[++tl]=to[p];
    return ne[tt]>0;            
}
int dinic(int v,int flow)
{
    if(v==tt) return flow;
    if(ne[v]==-1) return 0;

    int re=0;
    for(int p=con[v];p&&flow;p=nxt[p])
        if(c[p]>f[p]&&ne[to[p]]==ne[v]+1)
        {
            int o=dinic(to[p],min(flow,c[p]-f[p]));
            f[p]+=o;f[p^1]-=o;
            re+=o;flow-=o;
        }
    if(!re) ne[v]=-1;
    return re;  
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
        scanf("%d",&P[i]);
    for(int i=0;i<=n;i++)
        scanf("%d",&T[i]);
    for(int i=0;i<=n;i++)
        scanf("%d",&Q[i]);
    for(int i=0;i<=n;i++)
        scanf("%d",&S[i]);  
    for(int i=0;i<=n;i++)
        for(int j=0;j<=200;j++)
            fre[i][j]=T[i];     
    while(1)
    {
        int t,x;
        scanf("%d%d",&t,&x);
        if(t==-1&&x==-1) break;
        for(int i=x;i<=n;t+=Q[i],i++)
            for(int j=max(t+Q[i]-S[i]+1,0);j<t;j++)
                fre[i][j]--;
    }
    ss=(n+1)*(mxt+1)+1,tt=(n+1)*(mxt+1)+2;
    for(int j=0;j<=mxt;j++)
        ins(ss,G(0,j),inf);
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=mxt-S[i];j++)
            ins(G(i,j),i==n?tt:G(i+1,j+S[i]),fre[i][j]);
        for(int j=0;j<mxt;j++)
            ins(G(i,j),G(i,j+1),P[i]);
    }

    while(bfs()) ans+=dinic(ss,inf);//puts("!!!!");
    printf("%d",ans);       
    return 0;
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值