计蒜客:热爱工作的蒜蒜(最短路)

题目链接

热爱工作的蒜蒜

Time limit:1000ms Memory limit:262144K


Problem Description

众所周知,蒜蒜是一名热爱工作的好员工,他觉得时间就是金钱,做事情总是争分夺秒。

这天晚上,蒜蒜一个人去吃晚饭。不巧的是,吃完饭以后就开始下雨了,蒜蒜并没有带雨伞出来。但是蒜蒜热爱工作,工作使他快乐,他要尽快赶回去写代码。

蒜蒜的公司在中关村,中关村这边地形复杂,有很多天桥、地下通道和马路交错在一起。其中,地下通道是可以避雨的,天桥和马路都没办法避。可以把中关村抽象成为 n 个点的地图(顶点编号为 1到 n),其中有 m1 条地下通道,有 m2 ​​ 条马路或者天桥,其中地下通道的长度为 1。蒜蒜吃饭的地方在 1 点,公司在 n 点。当然,蒜蒜虽然爱工作心切,但是他更不想淋很多雨,同时也不想浪费很多时间。于是他折中了一下——在保证他回到公司所走的路程总和小于等于 L 的情况下,他希望淋雨的路程和尽量的少。

请你赶紧帮热爱工作的蒜蒜规划一条路径吧,不要再让他浪费时间。

Input

T(1T20)

T

n(2n100)m1(0m150)m2(0m25000)L(1L108)

m1a,b(1a,bn)ab

m2u,v(1u,vn),c(1c106)uvc

所有路径都是双向的。

Output

对于每组数据,如果有满足要求的路径,输出一个整数,表示淋雨的路程长度,否则输出 1

Sample Input

3
4 2 2 6
1 2
2 3
1 4 5
3 4 4
4 2 2 5
1 2
2 3
1 4 5
3 4 4
4 2 2 4
1 2
2 3
1 4 5
3 4 4

Sample Output

4
5
-1

解题思路:

题目要求的是从1~n的一条路径,满足总路程<=L且淋雨(地上)路程最短,按照这个思路其实就是求一个地上路程的最短路,但这条路要满足总路程<=L的条件。理清思路后,求最短路可以用Dijkstra也可用spfa,只要在入队(加入集合)前判断一下是否能满足总路程<=L就可以了。

Code:

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;

const int INF=0x3f3f3f3f;
const int maxm=11111;
const int maxn=111;

struct EdgeNode
{
    int to;
    int w;
    int side;//地上为1,地下为0
    int next;
};

EdgeNode edges[maxm];
int N,M;
int head[maxn],edge;
bool vis[maxn];
queue <int> que;
int dis[maxn];//记录淋雨(地上)的长度
int total[maxn];//记录总长度
int n,m1,m2,L;

void addedge(int u,int v,int side,int c)
{
    edges[edge].side=side;
    edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}

void init()
{
    memset(head,-1,sizeof(head));
    edge=0;
}

void spfa(int s,int n)//单源最短路(s为起点,n为节点总数)
{
    int u;
    for (int i=0; i<=n; i++)
    {
        dis[i]=INF;
        total[i]=INF;
    }
    memset(vis,0,sizeof(vis));
    while (!que.empty()) que.pop();
    que.push(s);
    vis[s]=true;
    dis[s]=0;
    total[s]=0;
    while (!que.empty())
    {
        u=que.front();
        que.pop();
        vis[u]=false;
        for (int i=head[u]; i!=-1; i=edges[i].next)
        {
            int v=edges[i].to;
            int w=edges[i].w;
            int side=edges[i].side;
            //总长度小于L,地上距离较小的入队
            if (dis[v]>dis[u]+w*side&&total[u]+w<=L)
            {
                dis[v]=dis[u]+w*side;
                total[v]=total[u]+w;
                if (!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d%d%d",&n,&m1,&m2,&L);
        for(int i=0;i<m1;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            addedge(a,b,0,1);
            addedge(b,a,0,1);
        }
        for(int i=0;i<m2;i++)
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            addedge(u,v,1,c);
            addedge(v,u,1,c);
        }
        spfa(1,n);
        if(dis[n]==INF)
            printf("-1\n");
        else
            printf("%d\n",dis[n]);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值