Firdaws and Fatinah are living in a country with nn cities, numbered from 11 to nn.Each city has a risk of kidnapping or robbery.
Firdaws's home locates in the city uu, and Fatinah's home locates in the city vv.Now you are asked to find the shortest path from the city uu to the city vv that does not pass through any other city with the risk of kidnapping or robbery higher than ww, a threshold given by Firdaws.
Input Format
The input contains several test cases, and the first line is a positive integer TT indicating the number of test cases which is up to 5050.
For each test case, the first line contains two integers n~(1\le n\le 200)n (1≤n≤200) which is the number of cities, and q~(1\le q\le 2\times 10^4)q (1≤q≤2×104) which is the number of queries that will be given.The second line contains nn integers r_1, r_2, \cdots, r_nr1,r2,⋯,rn indicating the risk of kidnapping or robbery in the city 11 to nn respectively.Each of the following nnlines contains nn integers, the jj-th one in the ii-th line of which, denoted by d_{i,j}di,j, is the distance from the city ii to the city jj.
Each of the following qq lines gives an independent query with three integers u, vu,v and ww, which are described as above.
We guarantee that 1\le r_i \le 10^51≤ri≤105, 1\le d_{i,j}\le 10^5~(i \neq j)1≤di,j≤105 (i≠j), d_{i,i}=0di,i=0 and d_{i,j}=d_{j,i}di,j=dj,i.Besides, each query satisfies 1\le u,v\le n1≤u,v≤n and 1\le w\le 10^51≤w≤105.
Output Format
For each test case, output a line containing Case #x:
at first, where xx is the test case number starting from 11.Each of the following qq lines contains an integer indicating the length of the shortest path of the corresponding query.
样例输入
1
3 6
1 2 3
0 1 3
1 0 1
3 1 0
1 1 1
1 2 1
1 3 1
1 1 2
1 2 2
1 3 2
样例输出
Case #1:
0
1
3
0
1
2
题意:
两个人住在城市u,每天要去城市v,但是要经过一些城市和街道,而且每个城市都有危险值,要求找一条路的从城市u到城市v而且危险值不超过w的最短路径。
思路:
我们考虑floyd算法的动态规划解释,F(i,j,k)代表从i顶点到j顶点可以经过前k个顶点的最短路。对于本题,我们用F [ k ] [ i ] [ j ] 代表从i城市到j城市可以经过危险值是前k小的城市的最短路径。对于每个F [ k ] [ i ] [ j ] ,我们从:
一:从i城市到j城市,不经过危险值是第j小的城市。
二:从i城市到j城市,经过危险值是第j小的城市。
我们从这两种情况中选择最短路径小的那个填充到数组F [ k ] [ i ] [ j ]中去。
所以状态转移方程:
F [ k ] [ i ] [ j ]=min(F [ k-1 ] [ i ] [ j ] , F[ k-1 ] [ i ] [ id[ k ] ]+F [ k-1 ] [ id[ k ] ] [ j ] )
代码如下:
#include<bits/stdc++.h>
#define INT 999999999
using namespace std;
int e[210][210][210];//e[k][i][j]代表从i城市到j城市可以经过危险值前k小的城市的最短路径
int id[210];//id[i]代表危险值第i小的城市的编号
int danger[210];//danger[i]代表编号为i的城市的危险值
int t;
const int INF=0x3f3f3f3f;
bool cmp(int a,int b)//按照危险值从小到大对城市的编号排序
{
return danger[a]<danger[b];
}
int main()
{
scanf("%d",&t);
int z=1;
while (t--)
{
memset(e,INF,sizeof(e));//初始化e数组,给每个位置上的值都初始化为无穷大
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
id[i]=i;//这是没排序前的id数组
scanf("%d",&danger[i]);
}
sort(id+1,id+n+1,cmp);//按照危险值从小到大对id数组进行排序,排序后id[i]代表危险值是第i小的城市的编号
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&e[0][i][j]);//往e数组中放入原始值
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)//这三重for循环的意思是从i城市到j城市可以经过危险值是前k小的城市的最短路(e[k][i][j])
e[k][i][j]=min(e[k-1][i][j],e[k-1][i][id[k]]+e[k-1][id[k]][j]);//min函数中第一项代表从i城市到j城市不经过危险值是k-1小的城市,第二项是经过危险值是k-1小的城市
printf("Case #%d:\n",z);
z++;
//通过上面的三重for循环,我们把所有情况的任意两个城市的最短路径都给求了出来,下面问哪个,我们直接从数组中拿结果就行
while (m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
int k=0;
for(int i=1;i<=n;i++)//这个for循环目的是找出城市危险值小于或等于w的危险值最大的城市的危险值排名
if(danger[id[i]]<=w)//danger[id[i]]代表危险值为第i小的城市的具体危险值。
k=i;
printf("%d\n",e[k][u][v]);
}
}
}
对于正常的floyd算法,我们仅需要一个二维数组就可以实现求最短路了,但是,此题为什么还要用三维数组呢?
因为对于正常的二维数组的floyd算法,我们算出当前从i顶点到j顶点的最短路后就可以覆盖掉前面的求出的i顶点到j顶点的最短路了,对于正常的二维数组的floyd算法,我们不会保存之前求出的i顶点到j顶点当前最短路的结果。但是这个题不同,对于此题的问法,他是多次询问,而且他给定了中转顶点的一些限制,为了使得时间复杂度不会过高,我们就要用三维数组来保存我们之前算出的i顶点到j顶点当前最短路的结果,以便直接从三维数组中拿取。