GDUT Problem E: 逃票的chanming(2) SPFA (维护逃票次数最少基础上维护最小费用)

Description

这是一个神奇的国度。

这个国度一共有N个城市组成,让我们将他们编号为1~N,

城市与城市之间修建有发达的铁路系统,

而且不论距离有多远,乘客都只需要在入站的时候支付相应的车费,就可以沿着铁路到达另一个城市。

其中编号为i的城市所需要支付的车票为Ci元。

到达另一个城市之后,乘客只能出站,无法像地铁一样换乘。(这也叫发达?!)

这一天,chanming带着他的第一个月的工资K元来到了城市1。

他们想到城市N去寻找宝藏。

chanming用惊人的智慧发现了一个逃票的方法。并且在任何城市都可以通用。

并且第一次逃票之后,chanming将会爱上逃票的快感,

并将不会再使用钱购买车票(因为处女座的强迫症=。=)。

请问chanming最少需要逃几次票?

Input

输入数据包含多组数据。第一行是一个整数T(T<=30),表示测试数据的数量。

对于每组测试数据,第一行为三个整数,N,M,K(1<=N<=105,M<=106,K<=108),分别表示城市的数量,铁路的数量和chanming带的K元

接下来一行有N个整数,第i个表示Ci,也就是第i个城市入站的时候需要支付的车票费。

接下来M行,每行2个整数A,B(1<=A,B<=N),表示有一条单向铁路从城市A到城市B。

Output

对于每组数据,输出一行,表示最少的逃票次数。

若无论逃票多少次都无法到达,输出 -1.


#include<stdio.h>
#include<string.h>
#include<math.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int n,m;
long long k;
int cost[100010]; //记录每个站的票价
long long dist[100010]; //维护进第i 个站的最小费用
int ts[100010]; //维护第I个站前最少逃票次数
const long long INF=200000000000000; // INF>10的5 * 10 的8
vector<int>e[100010]; //记录边

void SPFA()
{
    queue<int>que;
    que.push(1);
    dist[1]=cost[1];
    ts[1]= (dist[1]<=k)?0:1;
    vector<int>::iterator it;
    while(que.size())
    {
        int cur=que.front();que.pop();
        for(it=e[cur].begin();it!=e[cur].end();it++)
        {
            if(*it==n){
                dist[n]=min(dist[cur],dist[n]); //这一步只是为了方便判断是否可以到达
                ts[n]=min(ts[n],ts[cur]);
            }
            else{
                long long val=dist[cur]+cost[*it];    //维护逃票次数最少基础上维护最小费用
                int step= val<=k?0:ts[cur]+1;
                if(ts[*it]>step){
                    ts[*it]=step;
                    dist[*it]=val;
                    que.push(*it);
                }else if(ts[*it]==step&&dist[*it]>val){
                      dist[*it]=val;
                      que.push(*it);
                }
            }
        }
    }

}
int deal()
{
    if(dist[n]==INF) return -1;
    else return ts[n];
}
int main()
{

     //freopen("in.in","r",stdin);
     int T;
     scanf("%d",&T);
     while(T--)
     {
        scanf("%d%d",&n,&m);
        cin>>k;
        for(int i=1;i<=n;i++)
            scanf("%d",&cost[i]);
        for(int i=1;i<=n;i++)  // void clear()
        {
            e[i].clear();
            ts[i]=100010;
            dist[i]=INF;
        }
        int a,b;
        while(m--)
        {
            scanf("%d%d",&a,&b);
            if(a!=b&&a!=n) e[a].push_back(b);
        }
        SPFA();
        printf("%d\n",deal());
     }
     return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值