TFOJS-1138

Find the Path

Time Limit:20000MS Memory Limit:32768K

    如果这一题把每个城市的警察的数量这个限制去掉的话,我想每个人都能轻易的做出来,那样的话直接使用Floyd算法求出每个城市之间的最短路便可以了。

    但这个问题的难点就在它要限制在每个城市的警察数量(cops)不超过k的前提下的最短路,一开始没什么思路,一些方法因为有些方面不足也都被摒弃了。这是应该想着去对Floyd加以改动,使之适合这一题,我们都知道Floyd的第一层(for(k=0;k<n;k++))是按照从第1个节点到第N个节点的顺序来更新的,当更新到第k个节点时所得到的最短路径d[i][j]是i到j由前k个结点所组成的最短路径,这时不一定是全局最优的最短路径,但是肯定是由前k个城市组成的最短路径。以此为契机,先把每个城市的cops按照从小到大的顺序排序,Floyd的第一层按照cops从小到大来更新ans[k][i][j],ans[k][i][j]表示前k个结点更新出来的从i到j的最短路径,如果cops[k]是小于等于给定限制的最大的城市里的cops,那么ans[k][i][j]就是query的答案。

    对于每个query,使用upper_bound()函数可以得到第一个刚好小于等于cops[k]的地址,然后减去cops就是下标。在判断下ans[k][i][j]是否是给定的初始无穷大值就知道ans[k][i][j]是否是答案。

#include <iostream>
#define MAX_INT 1073741823
using namespace std;
int n,m,d[202][202];
int pos[202],cops[202];
int ans[202][202][202];
inline bool cmp(int i,int j)
{  return cops[i]<cops[j]; }
void readin(void)
{
     int i,j,u,v,k,query;
     cin >> n >> m;
     for(i=0;i<n;i++)
     {
         cin >> cops[i];
         pos[i]=i;
     }
     for(i=0; i<n; i++)
       for(j=0; j<n; j++)
         if(i==j) d[i][j]=0;
         else d[i][j]=MAX_INT; 
     for(i=0; i<m; i++)
     {
        cin >> u >> v >> k;
        d[u][v]=d[v][u]=k;
     }
     sort(pos,pos+n,cmp);
     for(i=0; i<n; i++)
        for(j=0; j<n; j++)
           ans[0][i][j] = d[i][j];
     
     for(k=0; k<n; k++)
     {
        v=pos[k]; 
        for(i=0; i<n; i++)
          for(j=0; j<n; j++)
          {
            ans[k+1][i][j]=ans[k][i][j];
            if(ans[k+1][i][j]>ans[k][i][v]+ans[k][v][j])
               ans[k+1][i][j]=ans[k][i][v]+ans[k][v][j];
          }
     }
     sort(cops,cops+n);
     cin >> query;
     while(query--)
     {
        cin >> u >> v >> k;
        i=upper_bound(cops,cops+n,k)-cops;
        if(ans[i][u][v]>=MAX_INT) cout << -1 << endl;
        else cout << ans[i][u][v] << endl;
     }
}
int main()
{
    int test;
    cin >> test;
    while(test--)
    {
       readin();
       if(test) cout << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值