最短路径 - URI在线评判1640

时间:2016-09-01 14:13:06

标签: c++ graph dijkstra shortest-path

我试图在uri在线评判中传递此代码,但我不知道我的错误在哪里,我所做的所有测试都有效。

链接问题是这样的: https://www.urionlinejudge.com.br/repository/UOJ_1640_en.html

问题的描述是:

运输公司经常需要将货物从一个城市运送到另一个城市。这家运输公司与一家连锁酒店达成了特殊协议,允许其司机免费入住该连锁酒店。司机每天最多可以开车10小时。运输公司希望找到从起始城市到目的地城市的路线,以便司机可以在酒店连锁的其中一家酒店过夜,并且他需要从一家酒店开车至最多10个小时。下一个酒店(或目的地)。当然,也应尽量减少交付货物所需的天数。 输入

输入文件包含多个测试用例。每个测试用例以包含整数n((2≤n≤10000)的行开始,该行是规划路径时要考虑的城市数。为简单起见,城市的编号从1到n,其中1是起始城市,n是目的地城市。下一行包含一个整数h,后跟数字c1,c2,...,ch,表示连锁酒店所在城市的数量。您可以假设0≤h≤min(n,100)。每个测试用例的第三行包含一个整数m(1≤m≤105),即计划路径时要考虑的道路数。以下m行描述了道路。每条道路由一条包含3个整数a,b,t(1≤a,b≤n且1≤t≤600)的线描述,其中a,b是由道路连接的两个城市,t是时间驾驶员从道路的一端开到另一端需要的时间。输入由n = 0终止。 输出

对于每个测试案例,打印一行,其中包含运输公司必须预订的从城市1到城市n的最小酒店数量。如果找不到司机必须每天最多开车10小时的路线,请改为打印-1。

我的尝试解决方案在我的github上: https://github.com/h31nr1ch/uri/blob/master/1640.cpp

#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <limits> // for numeric_limits
#include <set>
#include <utility> // for pair
#include <algorithm>
#include <iterator>
using namespace std;

typedef long long int vertex_t;
typedef double weight_t;
const weight_t max_weight = numeric_limits<double>::infinity();

struct neighbor {
  vertex_t target;
  weight_t weight;
  weight_t current;
  bool hotel;
  neighbor(vertex_t arg_target, weight_t arg_weight,weight_t arg_current,bool arg_hotel):target(arg_target), weight(arg_weight),current(arg_current),hotel(arg_hotel){ }
};

typedef vector<vector<neighbor> > adjacency_list_t;

void DijkstraComputePaths(vertex_t source,adjacency_list_t &adjacency_list, vector<weight_t> &min_distance, vector<vertex_t> &previous,vector<vertex_t> &hoteis,vector<vertex_t> &weights,vector<bool> &tHotel){
  int n = adjacency_list.size();
  min_distance.clear();
  min_distance.resize(n, max_weight);
  min_distance[source] = 0;
  previous.clear();
  previous.resize(n, -1);
  weights.clear();
  weights.resize(n,0);
  tHotel.clear();
  tHotel.resize(n,false);
  set<pair<weight_t, vertex_t> > vertex_queue;
  vertex_queue.insert(make_pair(min_distance[source], source));
  while (!vertex_queue.empty()){
    weight_t dist = vertex_queue.begin()->first;
    vertex_t u = vertex_queue.begin()->second;
    vertex_queue.erase(vertex_queue.begin());
    vector<neighbor> &neighbors = adjacency_list[u];
    for (vector<neighbor>::iterator neighbor_iter = neighbors.begin(); neighbor_iter != neighbors.end(); neighbor_iter++){
      vertex_t v = neighbor_iter->target;
      weight_t weight = neighbor_iter->weight;
      weight_t current= neighbor_iter->current;
      weight_t distance_through_u = dist + weight;
      if (distance_through_u < min_distance[v]) {
        bool l=true;
        bool ho=false;//Variavel criada para falar se dormiu no hotel ou nao
        //if(distance_through_u>600){
        if(weight+weights[u]>600){
          //Procurando por um hotel
          if(hoteis.size()==0)
            l=false;
          for(vector<vertex_t>::iterator it=hoteis.begin();it!=hoteis.end();it++){
            if(*it==u){
              l=true;
              ho=true;
              break;
            }
            else{
              l=false;
            }
          }
        }
        if(l){
          if(ho){
            tHotel[v]=true;
            weights[v]=weight;
            //cout<<"O nó u= "<<u<<" e nó v= "<<v<<" precisaram de hotel! Entao o peso é: "<<weights[v]<<endl;
          }
          else{
            tHotel[v]=false;
            weights[v]=distance_through_u;
            //cout<<"O nó u= "<<u<<" e nó v= "<<v<<" NÃO precisaram de hotel! Entao o peso é: "<<weights[v]<<endl;
          }
          vertex_queue.erase(make_pair(min_distance[v], v));
          min_distance[v] = distance_through_u;
          previous[v] = u;
          vertex_queue.insert(make_pair(min_distance[v], v));
        }
      }
    }
  }
}

list<vertex_t> DijkstraGetShortestPathTo( vertex_t vertex, const vector<vertex_t> &previous){
   list<vertex_t> path;
   for (;vertex != -1; vertex = previous[vertex])
     path.push_front(vertex);
   return path;
}

int main(){
  int n=1,m,x,y,w,v;
  while(n!=0){
    vector<vertex_t> hoteis;
    cin>>n;
    adjacency_list_t adjacency_list(n);
    if(n==0)
      break;
    cin>>v;
    for(int i=0;i<v;i++){
      cin>>x;
      hoteis.push_back(x-1);
    }
    cin>>m;
    for(int i=0;i<m;i++){
      cin>>x>>y>>w;
      adjacency_list[x-1].push_back(neighbor(y-1,w,0,false));
    }
    vector<weight_t> min_distance;
    vector<vertex_t> previous;
    vector<vertex_t> weights;
    vector<bool> tHotel;
    DijkstraComputePaths(0, adjacency_list, min_distance, previous,hoteis,weights,tHotel);
    //cout << "Distance from 0 to "<<n-1<<" : " << min_distance[n-1] << endl;
    list<vertex_t> path = DijkstraGetShortestPathTo(n-1, previous);
    //cout<<"Weights: ";
    //copy(min_distance.begin(),min_distance.end(),ostream_iterator<vertex_t>(cout," "));
    //cout<<endl;
    //cout << "Path : ";
    //copy(path.begin(), path.end(), ostream_iterator<vertex_t>(cout, " "));
    //cout<<endl;
    int total=0;
    //for(vector<bool>::iterator it=tHotel.begin();it!=tHotel.end();it++){
    //  cout<<*it<<" ";
    //}
    for(list<vertex_t>::iterator it=path.begin();it!=path.end();it++){
      if(tHotel[*it]==1)
        total++;
    }
    //cout<<endl;
    if(min_distance[n-1]==max_weight){
      cout<<"-1\n";
    }
    else{
      cout<<total<<endl;
    }
  }
  return 0;
}

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

首先计算酒店之间的最短旅行时间可以简化问题。这意味着您可以从每家酒店计算出通过道路到达其他所有酒店所需的最短时间。

然后,计算从城市1到每个酒店的最短距离,类似于城市n

使用新距离,使用酒店与其他2个城市之间的最短路径形成新图表。如果路径长度为>600,则忽略它(这意味着不要将其放在新图中)。然后使用Dijkstra,每条边的权重为1。这将为您提供到达目的地所需的最少酒店数量+1。如果新图表中没有路径,那么就不可能。

该算法将采用O((k+2)m log n + m log (k+2)) = O(km log n)