LA 5854 Long Distance Taxi (SPFA 变型) - from lanshui_Yang

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值