[JSOI2016]飞机调度

题目描述

作为一个旅行达人以及航空公司的金卡会员,你每一年的飞行里程可以绕赤道几周了。你发现,航空公司为了提高飞机的使用率,并不是简单的一条航线使用一架飞机来回飞,而是会让同一架飞机连续不停地飞不同的航线,甚至有的时候为了能够完成飞机的调度,航空公司还会增开一些临时航线——在飞机转场的同时顺路捎一些乘客。你研究了一下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个航班。

最小路径覆盖

把每个航线看做一个点。
如果走完一条航线后可以再另一个航线开始前到达其起点城市并完成修飞机,那么这两点间连有向边。
最后出来的是一个DAG。
然后做最小路径覆盖即可。
至于如何知道两点间能否连边,做一次floyd就好。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=500+10,maxm=2500000+10,inf=100000000;
int h[maxn*2],now[maxn*2],d[maxn*2],go[maxm],dis[maxm],fx[maxm],next[maxm],p[maxn];
bool bz[maxn*2];
int tim[maxn][maxn],dist[maxn][maxn];
struct dong{
    int x,y,d;
} a[maxn];
int i,j,k,l,s,t,n,m,tot,ans;
void add(int x,int y,int z,int d){
    go[++tot]=y;
    dis[tot]=z;
    fx[tot]=tot+d;
    next[tot]=h[x];
    h[x]=tot;
}
int dfs(int x){
    bz[x]=1;
    if (x==t){
        ans++;
        return 1;
    }
    int r=now[x],k;
    while (r){
        if (!bz[go[r]]&&dis[r]&&d[x]==d[go[r]]+1){
            k=dfs(go[r]);
            if (k){
                dis[r]--;
                dis[fx[r]]++;
                now[x]=r;
                return 1;
            }
        }
        r=next[r];
    }
    now[x]=0;
    return 0;
}
bool change(){
    int i,r,tmp=inf;
    fo(i,s,t)
        if (bz[i]){
            r=h[i];
            while (r){
                if (!bz[go[r]]&&dis[r]&&d[go[r]]+1-d[i]<tmp) tmp=d[go[r]]+1-d[i];
                r=next[r];
            }
        }
    if (tmp==inf) return 0;
    fo(i,s,t)
        if (bz[i]) d[i]+=tmp;
    return 1;
}
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]);
    fo(i,1,n)
        fo(j,1,n){
            scanf("%d",&tim[i][j]);
            if (i!=j) dist[i][j]=tim[i][j]+p[j];else dist[i][j]=tim[i][j];
        }
    fo(k,1,n)
        fo(i,1,n)
            if (i!=k)
                fo(j,1,n)
                    if (j!=k)
                        if (i!=j)
                            if (dist[i][k]+dist[k][j]<dist[i][j])
                                dist[i][j]=dist[i][k]+dist[k][j];
    fo(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
    s=1;t=2*m+2;
    fo(i,1,m)
        fo(j,1,m)
            if (i!=j){
                l=a[i].d+tim[a[i].x][a[i].y]+p[a[i].y]+dist[a[i].y][a[j].x];
                if (l<=a[j].d){
                    add(i*2,j*2+1,1,1);
                    add(j*2+1,i*2,0,-1);
                }
            }
    fo(i,1,m){
        add(s,i*2,1,1);
        add(i*2,s,0,-1);
        add(i*2+1,t,1,1);
        add(t,i*2+1,0,-1);
    }
    do{
        fill(bz+s,bz+t+1,0);
        fo(i,s,t) now[i]=h[i];
        while (dfs(s)) fill(bz+s,bz+t+1,0);
    }while (change());
    printf("%d\n",m-ans);
    fclose(stdin);fclose(stdout);
    return 0;
}

你可能感兴趣的:([JSOI2016]飞机调度)