航班安排
题解
很简单的一道网络流
看到这道题应该是十分容易想起费用流。
很明显,如果我们将每个单位的时间的机场分别建点再出来连的话是明显会T的,因为这样边的数量达到了
n
(
T
+
m
)
n(T+m)
n(T+m)的级别。
考虑不通过机场来建点,通过询问来建点。
将每个询问拆成入点与出点,两者之间连流量为
1
1
1,费用为
−
c
-c
−c的边,再在所有的询问之间判断哪些出点能够到达哪些入点,在它们间连边。最后再连出起点与终点的边即可。
至于总共
K
K
K台飞机的限制,只要再加一个超源点,将它与源点之间边的流量设为
K
K
K即可。
这种方法建出来点数是
2
m
+
4
2m+4
2m+4,边数是
m
2
m^2
m2级别的。
时间复杂度
O
(
K
m
3
)
O\left(Km^3\right)
O(Km3),当然,如果它卡了spfa的话。但事实证明没有
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 205
#define MAXT 3005
#define MAXM 505
#define MAXX 250005
#define reg register
typedef long long LL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
const LL inf=0x7f7f7f7f7f7f;
template<typename _T>
inline void read(_T &x){
_T f=1;x=0;char s=getchar();
while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,K,Ti,head[MAXM],tot,pre[MAXM],pw[MAXM],dis[MAXM],cnt,S1,T1;
int tim[MAXN][MAXN],pai[MAXN][MAXN],S,T,fl[MAXM];bool link[MAXN][MAXT];
queue<int> q;bool vis[MAXM];
struct edge{int to,nxt,flow,paid,op;}e[MAXX];
struct ming{int a,b,s,t;}s[MAXN];
inline void addEdge(const int u,const int v,const int w,const int f){e[++tot]=(edge){v,head[u],f,w};head[u]=tot;}
inline void addedge(const int u,const int v,const int f,const int w){addEdge(u,v,w,f);e[tot].op=tot+1;addEdge(v,u,-w,0);e[tot].op=tot-1;}
inline pii EK(){
int mf=0,res=0;
while(1){
while(!q.empty())q.pop();
for(reg int i=1;i<=cnt;++i)dis[i]=INF,fl[i]=0;
q.push(S);dis[S]=0;vis[S]=1;fl[S]=INF;
while(!q.empty()){
const int u=q.front();q.pop();vis[u]=0;if(!fl[u])continue;
for(reg int i=head[u];i;i=e[i].nxt){
const int v=e[i].to;
if(dis[v]>dis[u]+e[i].paid&&e[i].flow>0){
dis[v]=dis[u]+e[i].paid;pre[v]=u;pw[v]=i;
if(!vis[v])q.push(v),vis[v]=1,fl[v]=min(fl[u],e[i].flow);
}
}
}
if(dis[T]>INF-1)break;mf+=fl[T];res+=fl[T]*dis[T];
for(reg int i=T;i^S;i=pre[i])e[pw[i]].flow-=fl[T],e[e[pw[i]].op].flow+=fl[T];
}
return make_pair(mf,res);
}
signed main(){
read(n);read(m);read(K);read(Ti);S=m*2+1;T=m*2+2;S1=m*2+3;cnt=T1=m*2+4;
for(reg int i=0;i<n;++i)for(reg int j=0;j<n;++j)read(tim[i][j]);
for(reg int i=0;i<n;++i)for(reg int j=0;j<n;++j)read(pai[i][j]);
for(reg int i=1;i<=m;++i){
int c;read(s[i].a),read(s[i].b),read(s[i].s);read(s[i].t);read(c);
if(tim[0][s[i].a]>s[i].s||s[i].t+tim[s[i].b][0]>Ti)continue;
addedge(S1,2*i-1,1,pai[0][s[i].a]);addedge(2*i,T1,1,pai[s[i].b][0]);addedge(2*i-1,2*i,1,-c);
for(reg int j=1;j<i;++j){
if(s[i].s-tim[s[j].b][s[i].a]>=s[j].t)addedge(2*j,2*i-1,1,pai[s[j].b][s[i].a]);
if(s[i].t+tim[s[i].b][s[j].a]<=s[j].s)addedge(2*i,2*j-1,1,pai[s[i].b][s[j].a]);
}
}
addedge(S,S1,K,0);addedge(T1,T,K,0);
pii ans=EK();printf("%d\n",-ans.second);
return 0;
}