2018 ICPC 银川 F.Moving On(floyd变形)

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 nn lines 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 iito 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^5, 1 \le d_{i,j} \le 10^5 (i \neq j), d_{i,i} = 01≤ri​≤105,1≤di,j​≤105(i​=j),di,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
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

分析

先将各城市按危险值排序,在跑floyd算法的时候按照危险值排序后的顺序,dp[i][j][k]表示从城市i到城市j借助排序后的前k个城市可以取到的最小距离,所以状态转移方程就是dp[i][j][k] = min( dp[i][j][k-1] , dp[i][name[k]][k-1] + dp[name[k]][j][k-1])

代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define maxn 300
int f[maxn][maxn][maxn];
int danger[maxn];
int name[maxn];

bool cmp(int a,int b){
    return danger[a]<danger[b];
}

int main(){
    int i, j, k, n, m, T, q;
    int cur = 0;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&q);
        for(i = 1; i <= n; i++){
            name[i] = i;
            scanf("%d",&danger[i]);
        }
        sort(name+1, name+1+n, cmp);
        for(i = 1; i <= n; i++){
            for(j = 1; j <= n; j++){
                scanf("%d",&f[i][j][0]);
            }
        }
        for(k = 1; k <= n; k++){
            for(i = 1; i <= n; i++){
                for(j = 1; j <= n; j++){
                    f[i][j][k] = min(f[i][j][k-1], f[i][name[k]][k-1]+f[name[k]][j][k-1]);
                }
            }
        }
        printf("Case #%d:\n",++cur);
        while(q--){
            int u, v ,w;
            scanf("%d%d%d",&u,&v,&w);
            int ans = 0;
            for(i = 1; i <= n; i++){
                if(danger[name[i]]<=w) ans = i;
            }
            printf("%d\n",f[u][v][ans]);
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值