【动态规划 floyd】SPOJ ACPC13

为什么rzz会把这题放在NOI模拟赛的T2?

题目大意

有一张$n$个点$m$条边的有向图,每条边有权值$w_i$。

定义一个任务$(a_i,b_i,c_i)$是如下一条路径:

  • 最多经过$c_i$条边
  • 路径上的边权$w_i$依次递增

要求回答$q$个独立询问的任务最小值。

$𝑛 \le 150,𝑐𝑖 \le 𝑚 \le 5000,𝑞 \le 1000,𝑤_i \le 5000$


题目分析

一道NOIP题吧

首先会想到一种dp:$f_{i,j,k}$表示对于当前处理的点$p$,路径另一端是$i$,已经过$j$条边,上一条边的权值是$k$的最小代价,时间复杂度$O(qn^2m)$。

注意到这个状态里的“上一条边权值为k”看上去很浪费,自然考虑如何去掉“w_i依次递增”的限制条件。

接下去的操作应该比较套路:$f_{i,j,k}$表示从$i$到$j$的递增路径上经过了$k$条边,然后将边从小到大加入图中,对于当前边$(u,v,w)$,就类floyd地枚举一个起始点$i$转移到$f_{i,v,k+1}$,这样就能保证路径边权是依次递增的。

时间复杂度$O(m \log m+n^2m+q)$.

 1 #include<bits/stdc++.h>
 2 const int maxn = 153;
 3 const int maxm = 5035;
 4 const int INF = 0x3f3f3f3f;
 5 
 6 struct Edge
 7 {
 8     int u,v,d;
 9     bool operator < (Edge a) const
10     {
11         return d < a.d;
12     }
13 }edges[maxm];
14 int T,n,m,q,f[maxn][maxn][maxn];
15 
16 int main()
17 {
18     for (scanf("%d",&T); T; --T)
19     {
20         memset(f, 0x3f3f3f3f, sizeof f);
21         scanf("%d%d%d",&n,&m,&q);
22         for (int i=1; i<=m; i++)
23             scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].d);
24         std::sort(edges+1, edges+m+1);
25         for (int i=1; i<=n; i++) f[i][i][0] = 0;
26         for (int t=1; t<=m; t++)
27         {
28             int u = edges[t].u, v = edges[t].v;
29             for (int i=1; i<=n; i++)
30                 for (int j=0; j<=n; j++)
31                     if (f[i][u][j]!=INF&&f[i][v][j+1] > f[i][u][j]+edges[t].d)
32                         f[i][v][j+1] = f[i][u][j]+edges[t].d;
33         }
34         for (int i=1; i<=n; i++)
35             for (int j=1; j<=n; j++)
36                 for (int l=1; l<=n; l++)
37                     f[i][j][l] = std::min(f[i][j][l], f[i][j][l-1]);
38         for (int u,v,c; q; --q)
39         {
40             scanf("%d%d%d",&u,&v,&c), c = std::min(c, n);
41             printf("%d\n",f[u][v][c]!=INF?f[u][v][c]:-1);
42         }
43     }
44     return 0;
45 }

 

 

END

posted @ 2019-04-21 18:59  AntiQuality  阅读(217)  评论(0编辑  收藏  举报