题目大意:直接抽象一下,有多个城市,这些城市之间有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 ; }