题目大意:直接抽象一下,有多个城市,这些城市之间有n条无向边,有一个旅行家(假设叫Mike),他有一辆摩托车,摩托车的邮箱大小为cap,其耗油量是 10千米/每升油,给定一个起点、一个终点和cap的值以及有加油站的城市 (Mike 可以在这些城市加满油),让你判断Mike是否可以从起点到达终点,如果可以,就求出路程的最小值,否则,就输出"-1"。
解题思路:这道题是一道变型的最短路问题,比普通的最短路难了许多。一般的最短路问题可以用SPFA解决,这道题也可以,但有些变化,这里队列中的对象是二维的,一个是顶点的编号,一个是摩托车还能走的路程。
请看代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<algorithm>
#define mem(a , b ) memset(a , b , sizeof(a))
using namespace std ;
const int MAXN = 3006 ;
const int INF = 0x7fffffff ;
struct Edge
{
int adj ;
int d ;
int next ;
}E[MAXN * 2] ;
int head[MAXN * 2] ;
int ed ;
struct Q
{
int Node ;
int C ;
};
int n , m , cap ;
string s1 , s2 ;
int st , e ;
map<string , int> mp ;
int cnt ;
bool inq[MAXN * 2][2006] ;
int dis[MAXN * 2][2006] ;
bool P[MAXN * 2] ; // 判断城市是否有加油站
char ss1[100] , ss2[100] ;
void chu()
{
mp.clear() ;
cnt = 0 ;
ed = 0 ;
mem(head , 0) ;
mem(dis , 0) ;
mem(P , 0) ;
mem(inq , 0) ;
}
void init()
{
chu() ;
scanf("%s%s" , ss1 , ss2) ;
s1 = string(ss1) ;
s2 = string(ss2) ;
if(mp.find(s1) == mp.end())
{
mp[s1] = ++ cnt ;
}
if(mp.find(s2) == mp.end())
{
mp[s2] = ++ cnt ;
}
st = mp[s1] ;
e = mp[s2] ;
cap *= 10 ;
int i ;
int td ;
int ta , tb ;
for(i = 0 ; i < n ; i ++)
{
scanf("%s%s" , ss1 , ss2) ;
s1 = string(ss1) ;
s2 = string(ss2) ;
scanf("%d" , &td) ;
if(!mp[s1])
{
mp[s1] = ++ cnt ;
}
if(!mp[s2])
{
mp[s2] = ++ cnt ;
}
ta = mp[s1] ;
tb = mp[s2] ;
if(td <= cap) // 建图
{
++ ed ;
E[ed].adj = tb ;
E[ed].d = td ;
E[ed].next = head[ta] ;
head[ta] = ed ;
++ ed ;
E[ed].adj = ta ;
E[ed].d = td ;
E[ed].next = head[tb] ;
head[tb] = ed ;
}
}
for(i = 0 ; i < m ; i ++)
{
scanf("%s" , ss1) ;
s1 = string(ss1) ;
if(!mp[s1])
{
mp[s1] = ++ cnt ;
}
int t = mp[s1] ;
P[t] = true ;
}
}
queue<Q> q ;
void spfa(Q u)
{
while (!q.empty()) q.pop() ;
q.push(u) ;
inq[u.Node][u.C] = true ;
while (!q.empty())
{
Q v = q.front() ;
q.pop() ;
inq[v.Node][v.C] = false ;
int i ;
i = head[v.Node] ;
while (i != 0)
{
Edge tv = E[i] ;
int vn = tv.adj ;
int vd = tv.d ;
int se = v.C - vd ;
if(P[vn]) // 注意此处
{
se = cap ;
}
if(v.C - vd >= 0 && dis[v.Node][v.C] + vd < dis[vn][se] )
{
dis[vn][se] = dis[v.Node][v.C] + vd ;
if(!inq[vn][se])
{
inq[vn][se] = true ;
Q tmp ;
tmp.Node = vn ;
tmp.C = se ;
q.push(tmp) ;
}
}
i = E[i].next ;
}
}
}
void solve()
{
int i , j ;
for(i = 1 ; i <= cnt ; i ++)
{
for(j = 0 ; j <= cap ; j ++)
dis[i][j] = INF ;
}
dis[st][cap] = 0 ;
Q Stmp ;
Stmp.Node = st ;
Stmp.C = cap ;
spfa(Stmp) ;
int MIN = INF ;
for(i = 0 ; i <= cap ; i ++)
{
MIN = min(MIN , dis[e][i]) ;
}
if(MIN == INF)
puts("-1") ;
else
printf("%d\n" , MIN) ;
}
int main()
{
while (scanf("%d%d%d" , &n , &m , &cap) != EOF)
{
if(n == 0 && m == 0 && cap == 0)
break ;
init() ;
solve() ;
}
return 0 ;
}