[JZOJ4465][JSOI2016?]飞机调度

来源:互联网 发布:profili软件下载 编辑:程序博客网 时间:2024/04/28 00:54

题目大意

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

1n,m5000px,ti,j1061Di106


题目分析

显然我们需要知道两个城市最短到达时间。我们定义Gi,j=ti,j+pj,使用Floyd对图G求多源最短路径d
然后对于任务ij,我们能在执行完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;}
0 0
原创粉丝点击