【GDOI模拟】飞机调度

Description

作为一个旅行达人以及航空公司的金卡会员,你每一年的飞行里程可以绕赤道几周了。你发现,航空公司为了提高飞机的使用率,并不是简单的一条航线使用一架飞机来回飞,而是会让同一架飞机连续不停地飞不同的航线,甚至有的时候为了能够完成飞机的调度,航空公司还会增开一些临时航线——在飞机转场的同时顺路捎一些乘客。你研究了一下GDOI著名航空公司GD Airways的常规直飞航线,你想知道,在最佳调度方案下,GD Airways最少需要多少架飞机才能成功执飞这所有的航线。
GDOI王国里有N个机场,编号为1到N。从i号机场到j号机场需要飞行Ti,j的时间。由于风向,地理位置和航空管制的因素,Ti,j和Tj,i并不一定相同。
此外,由于飞机降落之后需要例行维修和加油。当一架飞机降落k号机场时,需要花费Pk的维护时间才能再次起飞。
GD Airways一共运营M条航线,其中第i条直飞航线需要在Di时刻从Xi机场起飞,不经停,飞往Yi机场。
为了简化问题,我们假设GD Airways可以在0时刻在任意机场任意多架加油维护完毕的飞机;为了减少飞机的使用数,我们允许GD Airways增开任意多条临时航线以满足飞机的调度需要。
你想知道,理论上GD Airways最少需要多少架飞机才能完成所有这M个航班。

Solution

一眼就可以看出来是最小路径覆盖
根据常识最小路径覆盖=节点个数-最大匹配
如果航班i的飞机可以及时飞到航班j,那么就可以把i向j连边。
然后可以用KM算法(匈牙利算法),也可以打一个最大流。
其实还有一个贪心的算法(不知道是不是水的),这里就不谈了。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1007;
int i,j,k,l,t,n,m,ans,S,T;
int first[maxn*maxn],next[maxn*maxn],last[maxn*maxn],chang[maxn*maxn];
int p[maxn*maxn],a[maxn][maxn],f[maxn][maxn],d[maxn],fan[maxn*maxn],num;
int data[maxn*maxn],b[maxn*maxn],c[maxn*maxn],dd[maxn*maxn],dis[maxn*maxn];
void add(int x,int y,int z){
    last[++num]=y;
    next[num]=first[x];
    first[x]=num;
    chang[num]=z;
    fan[num]=num+1;
    last[++num]=x;
    next[num]=first[y];
    first[y]=num;
    chang[num]=0;
    fan[num]=num-1;
}
bool bfs(){
    int head=0,tail=1,now,i,ber;
    memset(data,0,sizeof(data));
    memset(d,0,sizeof(d));d[S]=1;
    ber=d[0];
    data[1]=S;
    while(head<tail){
        now=data[++head];
        for(i=first[now];i;i=next[i]){
            if(!d[last[i]]&&chang[i]>0){
                d[last[i]]=d[now]+1;
                data[++tail]=last[i];
            }
        }
    }
    return d[T]!=0;
}
int dinic(int x,int y){
    int i,j,k=0,l=0;
    if(x==T){
        return y;
    }
    for(i=first[x];i;i=next[i]){
        if(d[x]+1==d[last[i]]&&chang[i]>0){
            if(chang[i]>y)k=dinic(last[i],y);
            else k=dinic(last[i],chang[i]);
            if(k){
                l+=k;
                chang[i]-=k;chang[fan[i]]+=k;
                y-=k;
                if(y==0)break;
            }    
        }
    }
    if(l==0)d[x]=-1;
    return l;
}
int main(){
    freopen("flight.in","r",stdin);
    freopen("flight.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&p[i]);
    S=0,T=2*m+1;
    memset(f,127,sizeof(f));
    fo(i,1,n)fo(j,1,n){
        scanf("%d",&a[i][j]);
        if(i==j)f[i][j]=a[i][j];
        else f[i][j]=a[i][j]+p[j];
    }
    fo(k,1,n){
        fo(i,1,n){
            fo(j,1,n){
                if(i==j)continue;
                if(f[i][k]+f[k][j]<f[i][j]){
                    f[i][j]=f[i][k]+f[k][j];
                }
            }
        }
    }
    fo(i,1,m){
        scanf("%d%d%d",&b[i],&c[i],&dd[i]);    
        add(S,i,1);add(i+m,T,1);
    }
    fo(i,1,m){
        fo(j,1,m){
            if(i==j)continue;
            if(dd[i]+a[b[i]][c[i]]+p[c[i]]+f[c[i]][b[j]]<=dd[j]){
                add(i,j+m,1);
            }
        }
    }
    ans=m;
    while(bfs())ans-=dinic(S,0x7fffffff);
    printf("%d\n",ans);
}

你可能感兴趣的:(网络流,二分图最大匹配,匈牙利算法,GDOI,飞机调度)