HDU - 2290 Find the Path(最短路)

本文介绍了一道名为“FindthePath”的算法题目,通过使用Floyd算法解决多源最短路径问题,并考虑了路径上警察数量的限制条件。文章详细解释了解题思路及实现过程。
HDU - 2290
Time Limit: 5000MS Memory Limit: 64768KB 64bit IO Format: %I64d & %I64u

 Status

Description

Scofield is a hero in American show "Prison Break". He had broken the prison and started a big runaway. 
Scofield has a map of US with cities and bidirectional roads between them. The lengths of roads are known. Some cities get a lot of cops who are very troublesome. Now Scofield needs your help to arrange his runaway route. 

He needs a shortest path between two cities, while the quantity of the police in any city, except the start city and end city, on the route is no more than k. 

You should know that it is very hard to escape. Scofield is very smart but not good at computer. Now Scofield is in trouble, can you help him with your computer? 

Input

The input consists of several test cases. There is an integer T on the first line indicating the number of test cases. 
For each case, the first line consists of two integers N and M. N is the number of cities; M is the number of roads. The next line contains N integers C1, C2... CN, where Ci is the number of cops in city i. 

Then followed M lines, each line consists of three integer, u, v, w, indicating there is a road with length w between city u and city v. 

The following line consists of an integer Q, indicating the number of queries. Each of the following Q lines consists of three integers, u, v, k, indicating the query for the shortest path between city u and city v with limitation of k cops. 

Technical Specification 

1. T ≤ 20 
2. 2 ≤ N ≤ 200, 0 ≤ M ≤ n * (n – 1) / 2 
3. 0 ≤ Ci ≤ 1000,000,000 
4. 0 ≤ u, v < N, 0 ≤ w ≤ 1000, 0 ≤ k ≤ 1000,000,000 
5. 0 ≤ Q ≤ 100000 
6. There is no more than ONE road between two cities and no road between the same cities. 
7. For each query, u is not equal to v. 
8. There is ONE empty line after each test case. 

Output

For each query, output a single line contains the length of the shortest path. Output "-1" if you can't find the path. Please output an empty line after each test case.

Sample Input

1
4 4
100 2 3 100
0 1 1
0 2 1
1 3 2
2 3 3
2
0 3 2
0 3 1

Sample Output

3
-1

Source

题意是,有n个城市,m条无向路径,每个城市有ci个警察,给出q个询问,求从城市a到城市b,中途城市(不包括起点终点)警察数不超过k的权值和最小的路径

解法:由于起点和终点都不是固定的,所以要求多源最短路,很容易想到要用floyd。但是又有问题,每次询问都有k个警察的限制,怎么办呢。我们考虑floyd的原理,每次找到一个点,对经过那个点的边进行松弛,那么我们可以记录下每次松弛的结果。可以开个三维数组M[i][j][k],k表示松弛第k个点时的状态。然后进行floyd。问题在于,我怎么可以根据k来选择对应状态。floyd是从第一个点松弛到最后一个点,那我们只要根据ci的大小,对点进行排序,然后再floyd,就可以得到根据ci的大小floyd出来的状态。所以我们只要找到一个最大的ci,又不超过k的时候的状态,就找到结果了。

注意的地方:

1.由于c比较大,需要离散化。

2.每个case后都要有一个空行。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define X first
#define Y second
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int maxn=210;
const int INF=0x3f3f3f3f;
pii C[maxn];
int n,m,M[maxn][maxn][maxn],N[maxn];
void init()
{
    for (int i=0; i<n; i++)
        for (int j=0; j<n; j++)
            M[i][j][0]=INF;
}
void floyd()
{
    for (int k=1; k<=n; k++)
    {
        for (int l=0; l<n; l++)
            for (int r=0; r<n; r++)
                M[l][r][k]=M[l][r][k-1];
        for (int l=0; l<n; l++)if (M[l][k-1][k-1]!=INF)
            for (int r=0; r<n; r++)if (M[k-1][r][k-1]!=INF)
                if (M[l][r][k]>M[l][k-1][k]+M[k-1][r][k])//由于k从1开始,而下标从0开始,所以k-1
                    M[l][r][k]=M[l][k-1][k]+M[k-1][r][k];
    }
}
int main()
{
    int T,a,b,c,q;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        for (int i=0; i<n; i++)
            scanf("%d",&C[i].X),C[i].Y=i;
        sort(C,C+n);
        for (int i=0; i<n; i++)//进行离散
            N[C[i].Y]=i;
        init();
        for (int i=0; i<m; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            M[N[a]][N[b]][0]=M[N[b]][N[a]][0]=c;//这里用N[a]而不是a,因为N[a]存的才是排过序的
        }
        floyd();
        scanf("%d",&q);
        while (q--)
        {
            scanf("%d%d%d",&a,&b,&c);
            int ans=M[N[a]][N[b]][n];
            for (int i=0; i<n; i++)//n比较小,可以枚举,也可以二分
                if (C[i].X>c)
                {
                    ans=M[N[a]][N[b]][i];//这里的i其实是i-1+1,因为状态从1开始,要+1
                    break;
                }
            printf("%d\n",ans==INF?-1:ans);
        }
        puts("");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/scaugsh/p/5735201.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值