[JZOJ4465][JSOI2016?]飞机调度

题目大意

n 个城市,两两飞行时间为 ti,j ( ti,j 不一定等于 tj,i ,保证 ti,i=0 )。
m 条商务航线,要求在时刻 Di 从城市 Xi 飞往 Yi
飞机每次降落在城市 x ,需要 px 的维护时间,飞机在维护时不能起飞。
你可以增开任意条临时航线,从任意城市飞往另一个城市。请问至少需要多少架飞机,能保证商务航线能正常执行。
时刻 0 每个城市都有任意架维护完毕的飞机。

1n,m500 0px,ti,j106 1Di106

题目分析

显然我们需要知道两个城市最短到达时间。我们定义 Gi,j=ti,j+pj ,使用 Floyd 对图 G 求多源最短路径 d
然后对于任务 i j ,我们能在执行完 i 后执行 j 当且仅当 Di+GXi,Yi+dYi,XjDj
暴力枚举任务,得出它们是否能使用同一架飞机,得到一个 DAG ,我们对这个图进行最小路径覆盖即可。
时间复杂度 O(n3+m3) ,做最短路时千万不要使用 STL 的min,它的常数飞起。

听说有(li)人(fei)抱怨 SPFA 卡不过,我要吐槽:
|E| 为边集大小(本题 O(n2) ), |V| 为点集大小(本题 O(n) )。
单次 SPFA 复杂度是 O(k|E|) k 是一个玄学常数,在特定数据下可以达到上界 n ,故 SPFA 用在这题时,求多源最短路复杂度是 O(n4)
单次 Dijkstra 时间复杂度是 O(|V|log2|E|) ,故 Dijkstra 在这题求多源最短路时间复杂度 O(n3log2n)
因此乖乖♂去打 Floyd 吧。

代码实现

#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cctype>
#include <cstdio>
#include <cmath>

using namespace std;

int read()
{
        int x=0,f=1;
        char ch=getchar();
        while (!isdigit(ch))
        {
                if (ch=='-')
                        f=-1;
                ch=getchar();
        }
        while (isdigit(ch))
        {
                x=x*10+ch-'0';
                ch=getchar();
        }
        return x*f;
}

const int N=505;
const int M=505;

int dist[N][N],t[N][N];
bool G[M][M];
int X[M],Y[M],D[M];
bool vis[M];
int rp[N],be[M];
int n,m,ans;

int hungary(int x)
{
        vis[x]=true;
        for (int y=1;y<=m;y++)
                if (G[x][y]&&(!be[y]||!vis[be[y]]&&hungary(be[y])))
                {
                        be[y]=x;
                        return true;
                }
        return false;
}

int main()
{
        freopen("flight.in","r",stdin);
        freopen("flight.out","w",stdout);
        n=read(),m=read();
        for (int i=1;i<=n;i++)
                rp[i]=read();
        for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++)
                {
                        t[i][j]=read();
                        if (i!=j)
                            dist[i][j]=t[i][j]+rp[j];
                        else
                            dist[i][j]=t[i][j];
                }
        for (int k=1;k<=n;k++)
                for (int i=1;i<=n;i++)
                        if (i!=k)
                                for (int j=1;j<=n;j++)
                                        if (i!=j&&j!=k)
                                                if (dist[i][j]>dist[i][k]+dist[k][j])
                                                        dist[i][j]=dist[i][k]+dist[k][j];
        for (int i=1;i<=m;i++)
        {
                be[i]=0;
                X[i]=read(),Y[i]=read(),D[i]=read();
                for (int j=1;j<i;j++)
                {
                        if (D[j]+t[X[j]][Y[j]]+rp[Y[j]]+dist[Y[j]][X[i]]<=D[i])
                                G[j][i]=true;
                        if (D[i]+t[X[i]][Y[i]]+rp[Y[i]]+dist[Y[i]][X[j]]<=D[j])
                                G[i][j]=true;
                }
        }
        ans=0;
        for (int i=1;i<=m;i++)
        {
                for (int j=1;j<=m;j++)
                        vis[j]=false;
                ans+=hungary(i);
        }
        ans=m-ans;
        printf("%d\n",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
}

你可能感兴趣的:(最短路,OI,匈牙利算法)