t题目链接:https://nanti.jisuanke.com/t/41290
思路:题目意思很容易想到floyd,但是由于危险度的限制,我们该怎么跑floyd呢。
一开始理解错题目了,以为u->v包括终点起点都不能超过给的危险度,不过看样例,好像只需要中间的城市不能超过危险度。
我们可以这么想,每个城市都有一个危险度,而floyd算法的本质是i到j经过前k个城市的转移,得到多源最短路,那么我们不妨
记录城市的编号和危险度,然后按城市的危险度排序,重新编号,危险度小的先跑floyd,然后f[k][i][j]表示经过前k个城市的最短路,
那么我们得出 f[k][i][j] = min(f[k-1][i][j],f[k-1][i][num[k]] + f[k-1][num[k][j]),从危险度小的推到危险度大的。
对于每个询问,我们只需要遍历按危险度编号的n个城市跑出的f[k][i][j],直到遍历到城市的危险度超出了危险度上限的那个f[k][u][v],
就是我们的答案了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <cmath> using namespace std; typedef long long LL; #define inf 1e9 #define rep(i, j, k) for (int i = (j); i <= (k); i++) #define rep__(i, j, k) for (int i = (j); i < (k); i++) #define per(i, j, k) for (int i = (j); i >= (k); i--) #define per__(i, j, k) for (int i = (j); i > (k); i--) const int N = 210; int f[N][N][N]; int n,q; int u,v,w; struct node{ int id; int ATK; friend bool operator<(const node& a,const node& b){ return a.ATK < b.ATK; } }W[N]; int main(){ int T; scanf("%d",&T); rep(o,1,T){ scanf("%d%d",&n,&q); rep(i,1,n){ W[i].id = i; scanf("%d",&W[i].ATK); } sort(W + 1,W + n + 1); rep(i,1,n) rep(j,1,n){ if(i == j) f[0][i][j] = 0; else f[0][i][j] = inf; } rep(i,1,n) rep(j,1,n){ scanf("%d",&w); f[0][i][j] = w; } // rep(i,1,n) cout << W[i].ATK << endl; // rep(i,1,n){ // rep(j,1,n) cout << f[0][i][j] << " "; // cout << endl; // } rep(k,1,n) rep(i,1,n) rep(j,1,n){ f[k][i][j] = min(f[k-1][i][j],f[k-1][i][W[k].id]+f[k-1][W[k].id][j]); } printf("Case #%d: ",o); int tmp; rep(i,1,q){ scanf("%d%d%d",&u,&v,&w); tmp = 0; rep(j,1,n) if(W[j].ATK <= w) tmp = j; printf("%d ",f[tmp][u][v]); } } getchar();getchar(); return 0; }