【GDOI模拟】飞机调度

来源:互联网 发布:淘宝赚佣金软件叫什么 编辑:程序博客网 时间:2024/04/28 17:31

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);}
1 0
原创粉丝点击