点击打开链接
考虑可以经停,从 i i i 到 j j j 包括维修在内的最短时间,这是可以通过 f l o y d O ( n 3 ) floyd\;O(n^3) floydO(n3) 求的
这样我们可以维护出一辆飞机是否可以先运行航班 x x x 再运行航班 y y y,可以通过上面的预处理维护出来
如果一辆飞机可以先运行航班 x x x 再运行航班 y y y,那么我们从 x x x 到 y y y 连一条边
考虑连出的图有何性质?显然这是 D A G DAG DAG
考虑简化后的问题:在一个 D A G DAG DAG 上,有最少的路径覆盖所有的点
这是一个经典问题
考虑拆点,把每个点拆成出点和入点,有边就从入点往出点连边,同时起点向所有入点连边,所有出点向终点连边
结论是: D A G DAG DAG 上的最少路径覆盖 = = = 总点数 − - − 最大匹配
证明:考虑某条路径必有终点,且只有终点对应的入点未匹配
反之,所以未匹配的点也一定是某条路径的终点,那么一个未匹配的点就可以对应一条路径
所以 路径的数目就是未匹配点的数目
需要 路径的数目尽量小,所以可得 D A G DAG DAG 上的最少路径覆盖 = = = 总点数 − - − 最大匹配
二分图跑 d i n i c dinic dinic 的时间复杂度为 O ( m n ) O(m\sqrt n) O(mn)
时间复杂度为 O ( n 3 + m 2 m ) O(n^3+m^2\sqrt m) O(n3+m2m)
#include
#define int long long
using namespace std;
const int N(1100),M(600000),inf(0x3f3f3f3f3f3f3f3f);
struct Node{
int x,y,d;
}airl[N];
int n,m,S,T,p[N],t[N][N],d[N][N];
int que[N],hh,tt,dis[N];
int e[M],ne[M],w[M],h[N],cur[N],idx;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void add(int x,int y,int z){ e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;}
bool bfs(){
memset(dis,0x3f,sizeof(dis));
hh=0,tt=-1,que[++tt]=S,dis[S]=0,cur[S]=h[S];
while(hh<=tt){
int u=que[hh++];
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
if(w[i]&&dis[u]+1<dis[v]) cur[v]=h[v],dis[v]=dis[u]+1,que[++tt]=v;
}
}
return dis[T]!=inf;
}
int find(int u,int limit){
if(u==T) return limit;
int res=0;
for(int i=cur[u];~i&&res<limit;i=ne[i]){
cur[u]=i;
int v=e[i];
if(w[i]&&dis[u]+1==dis[v]){
int t=find(v,min(w[i],limit-res));
if(!t) dis[v]=-1;
res+=t,w[i]-=t,w[i^1]+=t;
}
}
return res;
}
int dinic(){
int tot=0,add;
while(bfs()) while(add=find(S,inf)) tot+=add;
return tot;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++) p[i]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) t[i][j]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[i][j]=t[i][j]+p[i]+p[j];
for(int i=1;i<=n;i++) d[i][i]=p[i];
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
if(i!=k&&k!=j&&j!=i) d[i][j]=min(d[i][j],d[i][k]-p[k]+d[k][j]);
for(int i=1;i<=m;i++) airl[i].x=read(),airl[i].y=read(),airl[i].d=read();
memset(h,-1,sizeof(h));
S=0,T=2*m+1;
for(int i=1;i<=m;i++) add(S,i,1),add(i,S,0),add(i+m,T,1),add(T,i+m,0);
for(int i=1;i<=m;i++) for(int j=1;j<=m;j++)
if(airl[i].d+t[airl[i].x][airl[i].y]+d[airl[i].y][airl[j].x]<=airl[j].d){
// cout<
add(i,j+m,1),add(j+m,i,0);
}
printf("%lld",m-dinic());
return 0;
}