Recently, Shua Shua had a big quarrel with his GF. He is so upset that he decides to take a trip to some other city to avoid meeting her. He will travel only by air and he can go to any city if there exists a flight and it can help him reduce the total cost to the destination. There’s a problem here: Shua Shua has a special credit card which can reduce half the price of a ticket ( i.e. 100 becomes 50, 99 becomes 49. The original and reduced price are both integers. ). But he can only use it once. He has no idea which flight he should choose to use the card to make the total cost least. Can you help him?
Input
There are no more than 10 test cases. Subsequent test cases are separated by a blank line.
The first line of each test case contains two integers N and M ( 2 <= N <= 100,000
0 <= M <= 500,000 ), representing the number of cities and flights. Each of the following M lines contains “X Y D” representing a flight from city X to city Y with ticket price D ( 1 <= D <= 100,000 ). Notice that not all of the cities will appear in the list! The last line contains “S E” representing the start and end city. X, Y, S, E are all strings consisting of at most 10 alphanumeric characters.
Output
One line for each test case the least money Shua Shua have to pay. If it’s impossible for him to finish the trip, just output -1.
Sample Input
4 4
Harbin Beijing 500
Harbin Shanghai 1000
Beijing Chengdu 600
Shanghai Chengdu 400
Harbin Chengdu
4 0
Harbin Chengdu
Sample Output
800
-1
Hint
In the first sample, Shua Shua should use the card on the flight from
Beijing to Chengdu, making the route Harbin->Beijing->Chengdu have the
least total cost 800. In the second sample, there’s no way for him to get to
Chengdu from Harbin, so -1 is needed.
题意:有n个城市和m条航线,问起点到终点最省钱的方案,路线中有一条航线可以打五折
一道图论题,刚开始觉得很简单,觉得粘一个迪杰斯特拉的板子改一改就能过(每道题我都有这种想法,太菜了…),然后wa的莫名其妙,学姐讲完之后才知道是分层图,当时觉得听懂了,后来看代码又觉得不是太懂,又问了巨神韬哥,学到了一种相对分层图暴力一点的方法。
先反向建图,跑一遍迪杰斯特拉,将每一点到终点的最短路保存到一个数组中,然后在正向建图,再跑一遍迪杰斯特拉,将每一点到起点的最短路保存到数组中,然后遍历所给的每一条航线,起点到该航线起点的最短路加该航线终点到终点的最短路再加上该航线的一半即可,遍历的过程中将最小的答案保存下来即可!(字符串处理我采用了map映射)
#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
#include<string>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<ll,int>P;
const ll INF=0x7ffffffffff;
const int N=100500;
int n, m;
vector<P> G[N];
ll d[N];
ll e[N];
void dijkstra(int st) {
bool vis[N]= {false};
for(int i=0;i<N;++i){
d[i]=INF;
}
d[st]=0;
priority_queue<P,vector<P>,greater<P> >que;
que.push(P(0,st));
while(!que.empty()) {
int now=que.top().second,dis=que.top().first;
que.pop();
if(vis[now])continue;
vis[now]=true;
for(int i=0; i<G[now].size(); ++i) {
if(d[now]+G[now][i].first<d[G[now][i].second]) {
d[G[now][i].second]=d[now]+G[now][i].first;
que.push(P(d[G[now][i].second], G[now][i].second));
}
}
}
}
void dijkstra2(int st) {
bool vis[N]= {false};
for(int i=0;i<N;++i){
e[i]=INF;
}
e[st]=0;
priority_queue<P,vector<P>,greater<P> >que;
que.push(P(0,st));
while(!que.empty()) {
int now=que.top().second,dis=que.top().first;
que.pop();
if(vis[now])continue;
vis[now]=true;
for(int i=0; i<G[now].size(); ++i) {
if(e[now]+G[now][i].first<e[G[now][i].second]) {
e[G[now][i].second]=e[now]+G[now][i].first;
que.push(P(e[G[now][i].second], G[now][i].second));
}
}
}
}
ll u[5*N],v[5*N],w[5*N];
int main() {
while(~scanf("%d %d",&n,&m)) {
for(int i=1; i<=n; ++i) G[i].clear();
string a,b;
map<string,int>ms;
ll cut=1;
for(int i=1; i<=m; ++i) {
cin>>a>>b;
if(!ms[a]) {
ms[a]=cut++;
}
if(!ms[b]) {
ms[b]=cut++;
}
u[i]=ms[a];
v[i]=ms[b];
scanf("%lld",&w[i]);
G[v[i]].push_back(P(w[i],u[i]));
}
int st,ed;
cin>>a>>b;
if(!ms[a]) {
ms[a]=cut++;
}
if(!ms[b]) {
ms[b]=cut++;
}
st=ms[a];
ed=ms[b];
dijkstra2(ed);
for(int i=1; i<=n; ++i) G[i].clear();
for(int i=1;i<=m;++i){
G[u[i]].push_back(P(w[i],v[i]));
}
dijkstra(st);
ll ans=INF;
for(int i=1; i<=n; ++i) {
for(int j=0; j<G[i].size(); ++j) {
ans=min(ans,d[i]+G[i][j].first/2+e[G[i][j].second]);
}
}
if(d[ed]==INF) {
printf("-1\n");
} else {
printf("%lld\n",ans);
}
}
return 0;