#6177. 「美团 CodeM 初赛 Round B」送外卖2(floyed + 三进制枚举 )

Posted letlifestop

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#6177. 「美团 CodeM 初赛 Round B」送外卖2(floyed + 三进制枚举 )相关的知识,希望对你有一定的参考价值。

 题目大意:

一张  个点  条有向边的图上,有  个配送需求,需求的描述形式为 ,即需要从点  送到 , 在时刻  之后(包括  )可以在  领取货物,需要在时刻  之前(包括 )送达  ,每个任务只需完成一次。

图上的每一条边均有边权,权值代表通过这条边消耗的时间。在时刻  有一个工作人员在点  上,求他最多能完成多少个配送任务。

在整个过程中,可以认为领货跟交货都是不消耗时间的,时间只花费在路程上。当然在一个点逗留也是允许的。

具体思路:

首先对全图跑一个floyed,求一下各点之间的最短路。 然后分析每一个运送路线,三进制枚举,0表示当前的货物是没有取,1表示当前的货物是在路上的,2表示已经送达。

dp[i][j]表示当前在i点所有路线的送货状态为j时的最小花费。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define inf 0x3f3f3f3f
 5 #define LL_inf (1ll << 60)
 6 const int maxn = 20 + 5;
 7 const int mod = 1e9 + 7;
 8 int n, m, q;
 9 int dis[maxn][maxn];
10 struct node 
11     int s, t, l, r;
12  sto[15];
13 void floyed() 
14     for (int i = 1; i <= n; i++) 
15         for (int j = 1; j <= n; j++) 
16             for (int k = 1; k <= n; k++) 
17                 dis[j][k] = min(dis[j][k], dis[j][i] + dis[i][k]);
18             
19         
20     
21 
22 int third[maxn];
23 int dp[maxn][60005];
24 void solve(int maxstate) 
25     memset(dp, inf, sizeof(dp));
26     dp[1][0] = 0;
27     for (int i = 0; i <= maxstate; i++) 
28         for (int j = 1; j <= n; j++) 
29             for (int k = 1; k <= q; k++) 
30                 int tmp = i % third[k + 1] / third[k];
31                 if (tmp == 0 && dp[j][i] + dis[j][sto[k].s] <= sto[k].r) 
32                     dp[sto[k].s][i + third[k]] =
33                         min(dp[sto[k].s][i + third[k]], max(sto[k].l, dp[j][i] + dis[j][sto[k].s]));// 注意这里应该取最大值,有可能到了还没到规定的取货时间
34                 
35                 if (tmp == 1 && dp[j][i] + dis[j][sto[k].t] <= sto[k].r) 
36                     dp[sto[k].t][i + third[k]] = min(dp[sto[k].t][i + third[k]], dp[j][i] + dis[j][sto[k].t]);
37                 
38             
39         
40     
41 
42 int main() 
43     scanf("%d %d %d", &n, &m, &q);
44     for (int i = 1; i <= n; i++) 
45         for (int j = 1; j <= n; j++) 
46             if (i == j)
47                 dis[i][j] = 0;
48             else
49                 dis[i][j] = inf;
50         
51     
52     int st, ed, val;
53     while (m--) 
54         scanf("%d %d %d", &st, &ed, &val);
55         dis[st][ed] = min(dis[st][ed], val);
56     
57     for (int i = 1; i <= q; i++) 
58         scanf("%d %d %d %d", &sto[i].s, &sto[i].t, &sto[i].l, &sto[i].r);
59     
60     floyed();
61     third[1] = 1;
62     for (int i = 2; i <= q + 1; i++) 
63         third[i] = third[i - 1] * 3;
64     
65     solve(third[q + 1] - 1);
66     int ans = 0;
67     for (int i = 1; i <= n; i++) 
68         for (int j = 0; j <= third[q + 1] - 1; j++) 
69             if (dp[i][j] >= inf)
70                 continue;
71             int tmp = 0;
72             for (int k = 1; k <= q; k++) 
73                 tmp += ((j % third[k + 1] / third[k]) == 2 ? 1 : 0);
74             
75             ans = max(ans, tmp);
76         
77     
78     printf("%d\n", ans);
79     return 0;
80 

 

以上是关于#6177. 「美团 CodeM 初赛 Round B」送外卖2(floyed + 三进制枚举 )的主要内容,如果未能解决你的问题,请参考以下文章

Loj #6164. 「美团 CodeM 初赛 Round A」数列互质

「美团 CodeM 初赛 Round B」送外卖2---------------状压dp

「美团 CodeM 初赛 Round B」景区路线规划 概率DP

美团点评2018 CodeM A轮初赛

CodeM美团点评编程大赛初赛A轮

美团2017年CodeM大赛-初赛B轮 黑白树 (树形dp)