时间限制:1秒
空间限制:32768K
美团外卖日订单数已经超过1200万,实时调度系统是背后的重要技术支撑,其中涉及很多复杂的算法。下面的题目是某类场景的抽象。 一张 n 个点 m 条有向边的图上,有 q 个配送需求,需求的描述形式为( s_i , t_i , l_i , r_i ),即需要从点 s_i 送到 t_i, 在时刻 l_i 之后(包括 l_i)可以在 s_i 领取货物,需要在时刻 r_i 之前(包括 r_i)送达 t_i ,每个任务只需完成一次。 图上的每一条边均有边权,权值代表外卖配送员通过这条边消耗的时间。在时刻 0 有一个配送员在 点 1 上,求他最多能完成多少个配送任务。 在整个过程中,我们忽略了取餐与最后给用户递餐的时间(实际场景中这两个时间是无法省略的),只考虑花费在路程上的时间。另外,允许在一个点逗留。解题思路:状压每个货物的(未领、已领、已到)状态,每层状态保存最早到达点 i 的时间,每一层用 dijkstra 暴力更新最早时间
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <stack> #include <cmath> #include <map> #include <bitset> #include <set> #include <vector> #include <functional> using namespace std; #define LL long long const int INF = 0x3f3f3f3f; int n,m,q,u,v,c; int f[15],t[15],l[15],r[15],a[15],p[15]; int s[25],nt[405],e[405],cost[405]; int dp[60005][25]; bool vis[25]; int main() { while(~scanf("%d%d%d",&n,&m,&q)) { memset(s,-1,sizeof s); int cnt=1,x=1,ans=0; for(int i=1; i<=m; i++) { scanf("%d%d%d",&u,&v,&c); nt[cnt]=s[u],s[u]=cnt,e[cnt]=v,cost[cnt++]=c; } for(int i=1; i<=q; i++,x*=3)scanf("%d%d%d%d",&f[i],&t[i],&l[i],&r[i]),p[i]=x; memset(dp,INF,sizeof dp); dp[0][1]=0; for(int i=0; i<x; i++) { memset(vis,0,sizeof vis); for(int j=1; j<=n; j++) { u=0; for(int k=1; k<=n; k++) if(!vis[k]&&(!u||dp[i][k]<dp[i][u])) u=k; vis[u]=1; for(int k=s[u]; ~k; k=nt[k]) if(dp[i][u]+cost[k]<dp[i][e[k]]) dp[i][e[k]]=dp[i][u]+cost[k]; } for(int j=1,k=i; j<=q; j++,k/=3) a[j]=k%3; int sum=0; for(int j=1; j<=q; j++) { if(a[j]==0) { if(max(l[j],dp[i][f[j]])<dp[i+p[j]][f[j]]) dp[i+p[j]][f[j]]=max(l[j],dp[i][f[j]]); } else if(a[j]==1&&dp[i][t[j]]<=r[j]) { if(dp[i][t[j]]<dp[i+p[j]][t[j]]) dp[i+p[j]][t[j]]=dp[i][t[j]]; } else if(a[j]==2) sum++; } for(int j=1;j<=n;j++) if(dp[i][j]<INF) ans=max(ans,sum); } printf("%d\n",ans); } return 0; }