Olimpiada
iştirakçı-komandalardan biri evə elektrik qatarı
ilə qayıtmaq qərarına gəldi. Bu zaman uşaqlar
evə mümkün qədər tez çatmaq
istəyirlər. Təəssüf ki, heç də
bütün qatarlar olimpiadanın keçirildiyi
şəhərdən uşaqların yaşadıqları
stansiyaya qədər getmir. Daha təəssüf doğuran
odur ki, heç də bütün qatarlar onların
stansiyasından keçərkən orada dayanmır
(ümumiyyətlə, qatarlar yanından keçdikləri
stansiyaların heç də hamısının
uzaqlığında dayanmırlar).
Xətdəki bütün
stansiyalar 1-dən N-ə qədər
nömrələnmişdir. Bu zaman 1 nömrəli stansiya
olimpiadanın olduğu şəhərdə yerləşir
və 0 zamanında uşaqlar stansiyaya
gəlirlər. Uşaqların gəlmək istədikləri
stansiyanın nömrəsi E-dir.
Elektrik qatarlarının
verilmiş hərəkət qrafikinə görə
uşaqların evə çata biləcəkləri minimal
zamanı hesablayan proqramı tərtib edin.
Giriş
verilənləri. Giriş
faylında əvvəlcə N (2 ≤ N ≤ 100)
və E (2 ≤ E ≤ N)
ədədləri verilir. Sonra qatarların reyslərinin
sayını ifadə edən M (0 ≤ M ≤ 100)
ədədi verilir. Daha sonra qatarların M reysinin təsviri verilir. Qatarın
hər bir reysinin təsviri onun dayandığı
stansiyaların sayını ifadə edən Ki (2 ≤ Ki ≤ N)
ədədi ilə başlayır, daha sonra Ki ədəd cütlüyü
verilir, hər bir cütlüyün birinci ədədi
stansiyanın nömrəsini, ikincisi — qatarın bu stansiyada
dayanacağı zamanı (zaman 0-dan 109-a
qədər 10 tam ədədlə verilir) ifadə edir. Bir reys
daxilində stansiyalar zamana görə artan sıra ilə
sıralanmışdır. Bir reys ərzində qatar
həmişə bir istiqamətdə hərəkət edir –
ya şəhərdən, ya da şəhərə doğru.
Çıxış
verilənləri. Çıxış
faylına yeganə ədədi — uşaqların öz
stansiyalarına çata biləcəkləri minimal zamanı
verin. Əgər qatarların mövcud reysləri ilə onlar
evə çata bilməyəcəklərsə, –1 verin.
Giriş
verilənlərinə nümunə
5 3
4
2 1
5 2 10
2 2
10 4 15
4 5
0 4 17 3 20 2 35
3 1
2 3 40 4 45
Çıxış
verilənlərinə nümunə
20
qraflar – Dijkstra alqoritmi
Təpələrinin
sayı stansiyaların sayına bərabər olan qraf quraq.
Qrafın hər bir tili bir qatarın dayandığı qonşu
stansiyalar arasındakı hərəkətinə uyğundur.
Əgər From anında i stansiyasından
hərəkətə başlanılarsa, qatar qonşu j
stansiyasına To anında çatmış olur, onda i-dən j-yə
üzərində bir cüt ədəd (From, To)
yazılmış istiqamətlənmiş
til keçirək. Qrafı qonşuluq siyahısı
şəklində verəcəyik, buna görə də
hər bir til üçün onun istiqamətləndiyi
təpənin nömrəsini də yazmaq lazımdır.
Qurulmuş
istiqamətlənmiş qrafda Dijkstra alqoritmini icra edək. 1
təpəsindən e
təpəsinə ən qısa yolu tapırıq.
Misal
Beş stansiya və
dörd elektrik qatarının hərəkət qrafiki verilir.
Uyğun qraf aşağıdakı formadadır:
Dijkstra alqoritmini prioritetli növbə vasitəsilə
reallaşdırırıq. Növbənin elementləri
cütlüklərdir (mənbədən
məntəqəyə çatmaq üçün zaman və
təpənin nömrəsi). Beləliklə, növbədə
birinci olaraq həmişə mənbədən (Dijkstra
alqoritminin icra ediləcəyi başlanğıc
təpədən) çatacağımız ilk təpə
olacaq. Bu cütlüyü (Time, Vertex) ehtiva edən
Prior sinfini elan edək. Böyük və kiçik
operatorlarını təyin edək: o cütlük kiçik
sayılır ki, mənbəyə qədər olan
məsafə (Dist) ən kiçik olsun.
class Prior
{
public:
int Time, Vertex;
Prior(int Time, int Vertex)
: Time(Time), Vertex(Vertex) {}
int operator< (const Prior &a) const
{
return Time < a.Time;
}
int operator> (const Prior &a) const
{
return Time > a.Time;
}
};
İki qonşu stansiyanı birləşdirən
til sinfini elan edək. O növbəti atributları ehtiva edir:
·
vTo – qatarın getdiyi stansiyanın
nömrəsi;
·
timeFrom – cari stansiyadan qatarın yola
düşdüyü vaxt;
·
timeTo – qatarın vTo stansiyasını
çatdığı vaxt;
class Edge
{
public:
int vTo, timeFrom, timeTo;
Edge(int vTo, int timeFrom,
int timeTo)
: vTo(vTo), timeFrom(timeFrom), timeTo(timeTo) {}
};
Qraf sinfini elan edək. O təpə
nöqtələrinin n sayını
ehtiva edir və g qonşuluq siyahısı ilə
verilir.
class Graph
{
public:
int n;
vector<vector<Edge>
> g;
Graph(int n = 1) : n(n)
{
g = vector<vector<Edge> >(n);
}
İstiqamətlənmiş
tilin (From, To) əlavə edilməsi. Qatar From
stansiyasından timeFrom zaman anında yola düşür
və To stansiyasına timeTo zaman anında
çatır.
void AddEdge(int From,
int To, int timeFrom,
int timeTo)
{
g[From].push_back(Edge(To,timeFrom,timeTo));
}
Dijkstra
alqoritmi Source təpəsindən icra edilir. İkinci
arqument kimi time massivi verilir: time[i]
Source təpəsindən i təpəsinə
çatmaq üçün ən qısa zamanı ehtiva edir.
void Dijkstra(int Source,
vector<int> &time)
{
priority_queue<Prior, vector<Prior>, greater<Prior> > pq;
Növbəyə cütlüyü (0, Source)
yerləşdirək, hesab edirik ki, time[Source] zamanı 0-a
bərabərdir (Source təpəsindən onun
özünə getmək 0 zamanda mümkündür).
pq.push(Prior(0,Source)); time[Source] = 0;
while(!pq.empty())
{
int v = pq.top().Vertex;
int d = pq.top().Time; pq.pop();
Növbənin
başından cütlüyün (v, d)
çıxarılmasının yalan olduğunu
yoxlayırıq.
if (d > time[v]) continue;
v ilə qonşu olan to
təpəsinə baxırıq. (v, to) tilinin qısaltmasını
verməyə çalışırıq.
for(int i
= 0; i < g[v].size(); i++)
{
time[v] v stansiyasına getmək
üçün ən qısa zamanı ehtiva edir. Əgər
(v, to) tili qatarın v stansiyasından to
stansiyasına getmək üçün time[v]
zamanından erkən çıxdığı haqqında
informasiya ehtiva edərsə, onda biz bu qatara
çatmırıq.
if (g[v][i].timeFrom < time[v]) continue;
Tilin
getdiyi to tilini hesablayırıq.
int to = g[v][i].vTo ;
Əgər
to stansiyasına (v, to) tili ilə time[to]-dakı
zamandan erkən çatmaq mümkün olarsa, onda qısaltmanı
veririk və cütlüyü (time[to], to) növbəyə
yerləşdiririk.
if (time[to] > g[v][i].timeTo)
{
time[to] = g[v][i].timeTo;
pq.push(Prior(time[to],to));
}
}
}
}
};
Qraf
göstəricisi təyin edək.
Graph
*g;
Proqramın əsas hissəsi. Başlanğıc
stansiyadan bütün stansiyalara gedilməsi mümkün olan
ən qısa zamanları ehtiva edən time massivini verək.
scanf("%d
%d %d",&n,&e,&m);
g = new Graph(n+1);
time = vector<int>(n+1,INF);
Giriş verilənlərini
oxuyuruq. g qrafını
qururuq.
for(i = 0; i < m; i++)
{
scanf("%d",&stations); PrevStation = -1;
for(j = 0; j < stations; j++)
{
scanf("%d %d",&CurStation,&CurTime);
Qatar
PrevStation stansiyasından PrevTime zamanında çıxır,
növbəti CurStation stansiyasına yola düşür
və CurTime zaman anında stansiyaya çatır.
if (PrevStation != -1) g->AddEdge(PrevStation,CurStation,
PrevTime,CurTime);
PrevStation = CurStation; PrevTime = CurTime;
}
}
1
təpəsindən Dijkstra alqoritmini
icra edirik.
g->Dijkstra(1,time);
Cavabı
veririk.
if (time[e]
== INF) printf("-1\n");
else printf("%d\n",time[e]);