Objective: Berlin UVALive - 3645

本文介绍了一种利用网络流算法解决航班调度问题的方法,通过构建特定的图模型并使用最大流算法来确定从起点到终点的最大客流量。该模型考虑了中转时间和航班载客量等限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Objective: Berlin UVALive - 3645

网络流·最大流

http://www.cnblogs.com/20143605–pcx/p/5056844.html

题目大意:

有n个城市,m条航班。已知每条航班的起点和终点,还有每条航班的载客量、出发时间、到达时间。并且要求在任何一个城市(起点、终点除外)都至少要有30分钟的中转时间,求起点到终点的最大客流量。

题解:

将航线视作一个点,如果航线u能经过某城市中转到航线v,则从u连一条弧到v。构造好图之后拆点,将点u拆成u和u’,对于任意一个u,都连一条弧从u到u’,容量为航线上的载客量;对于节点u,从u’向u邻接的节点v连一条弧,容量为无穷大;增加源点s,从s向起点为出发点的航线u连一条弧,容量为无穷大,增加汇点t,从终点为目标点的航线v对应的v’向t连一条弧,容量也为无穷大。最后,答案就是最大流。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;

const int N = 20005;
const int M = 1e6+5;
const int INF = 0x3f3f3f3f;

int n,m,S,T;
string ss,tt;
int timelimit;

struct Node{
    string u,v; int c,st,et;
} fly[N];

struct edge{
    int to,cap,flow,next;
} e[M*2];
int head[N],ec=1;
void clear(){ memset(head,0,sizeof(head)); ec=1; }
void add(int a,int b,int cap){
    ec++; e[ec].to=b; e[ec].cap=cap; e[ec].flow=0;
    e[ec].next=head[a]; head[a]=ec;
}
void add2(int a,int b,int cap){
//  D(a); D(b); D(cap); E;
    add(a,b,cap); add(b,a,0);
}


bool vis[N]; int d[N];
bool bfs(){
    memset(vis,false,sizeof(vis));
    queue<int> q; q.push(S); vis[S]=true; d[S]=0;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(!vis[v] && e[i].cap>e[i].flow){
                d[v]=d[u]+1; vis[v]=true;
                q.push(v);
                if(v==T) return true;   
            }
        }
    }
    return false;
}

int dfs(int u,int a){
    if(u==T || a==0) return a;
    int flow=0, f;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(d[v]==d[u]+1 && (f=dfs(v,min(a,e[i].cap-e[i].flow)))){
            flow+=f; a-=f;
            e[i].flow+=f; e[i^1].flow-=f;
            if(a==0) break;
        }
    }
    if(a) d[u]=-1;
    return flow;
}

int mxf(){
    int flow=0;
    while(bfs()){
        flow+=dfs(S,INF);
    }
    return flow;
}

int func(int a,int b){
    int t1=(a/100)*60+a%100;
    int t2=(b/100)*60+b%100;
    return t1-t2;
}

int main(){
    freopen("a.in","r",stdin);
    while(cin>>n){
        clear();
        cin>>ss>>tt>>timelimit;
        cin>>m; S=0; T=m*2+1;
//      D(S); D(T); E;
        for(int i=1;i<=m;i++){
            cin>>fly[i].u>>fly[i].v>>fly[i].c>>fly[i].st>>fly[i].et;
        }
        for(int i=1;i<=m;i++){
            if(fly[i].u==ss) add2(S,i*2-1,INF);
            if(fly[i].v==tt && fly[i].et<=timelimit) add2(i*2,T,INF);
            add2(i*2-1,i*2,fly[i].c);
            for(int j=1;j<=m;j++){
                if(i==j) continue;
                if(fly[i].v==fly[j].u && func(fly[j].st,fly[i].et)>=30) 
                    add2(i*2,j*2-1,INF);
            }
        }
        int ans=mxf();
        printf("%d\n",ans); 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值