景驰无人驾驶 1024 编程邀请赛 A 热爱工作的蒜蒜 dijstra

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

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

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

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

输入格式

第一行输入测试组数 T(1 \le T \le 20)T(1≤T≤20)。

接下来 TT 组数据。

每一组数据的第一行输入四个整数 n(2 \le n \le 100)n(2≤n≤100),m_1(0 \le m_1 \le 50)m
​1
​​ (0≤m
​1
​​ ≤50),m_2(0 \le m_2 \le 5000)m
​2
​​ (0≤m
​2
​​ ≤5000),L(1 \le L \le 10^8)L(1≤L≤10
​8
​​ )。

接下里 m_1m
​1
​​ 行,每行输入两个整数 a, b(1 \le a, b \le n)a,b(1≤a,b≤n),表示 aa 和 bb 之间有一条地下通道。

接下里 m_2m
​2
​​ 行,每行输入三个整数 u, v(1 \le u, v \le n), c(1 \le c \le 10^6)u,v(1≤u,v≤n),c(1≤c≤10
​6
​​ ),表示 uu 和 vv 之间有一条长度为 cc 的马路或者天桥。

所有路径都是双向的。

输出格式

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

样例输入

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
样例输出

4
5
-1

注意有重边。
dist[i][j]表示到达i并且经过j条地下道的最小距离。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 105;
const LL inf = 0x3f3f3f3f3f3f3f3f;
int n, m1, m2;
LL l;
LL dp[MAXN][MAXN][2];
LL dis[MAXN][MAXN];
bool vis[MAXN];
void dij()
{
    memset(vis, false,sizeof(vis));
    for(int i=1; i<=n; ++i)
        dis[i][1]=dp[1][i][0];
    for(int i=1; i<=n; ++i)
        dis[i][0]=dp[1][i][1];
    int v;
    LL Min;
    vis[1]=true;
    for(int i=1; i<=n; ++i)
    {
        v=-1;
        Min=inf;
        for(int j=1; j<=n; ++j)
        {
            if(!vis[j])
            {
                for(int k=0; k<=m1; ++k)
                    if(Min>dis[j][k])
                        Min=dis[v=j][k];
            }
        }
        if(Min==inf)//没有这个判断,很多答案为-1的情况会错,错了好久。
            break;
        vis[v]=true;
        for(int j=1; j<=n; ++j)
        {
            if(!vis[j])
            for(int k=0; k<=m1; ++k)
            {
                if(dp[j][v][0]!=inf&&dis[j][k+1]>dis[v][k]+dp[j][v][0])
                    dis[j][k+1]=dis[v][k]+dp[j][v][0];
                else if(dp[j][v][1]!=inf&&dis[j][k]>dis[v][k]+dp[j][v][1])
                    dis[j][k]=dis[v][k]+dp[j][v][1];
            }
        }
    }
    LL ans=inf;
    for(int k=0; k<=m1; ++k)
    {
        if(dis[n][k]+k<=l)
            ans=min(ans,dis[n][k]);
    }
    if(ans!=inf)
        printf("%lld\n", ans);
    else
        printf("-1\n");
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int a, b;
        scanf("%d %d %d %lld", &n, &m1, &m2, &l);
        for(int i=0; i<=60; ++i)
            for(int j=0; j<=n; ++j)
                dis[j][i]=inf;

        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=n; ++j)
            {
                for(int k=0; k<=1; ++k)
                {
                    dp[i][j][k]=inf;
                }
            }
        }
        for(int i=1; i<=m1; ++i)
        {
            scanf("%d %d", &a, &b);
            dp[a][b][0]=dp[b][a][0]=0;
        }
        LL c;
        for(int i=1; i<=m2; ++i)
        {
            scanf("%d %d %lld", &a, &b, &c);
            if(dp[a][b][0]==inf&&c<dp[a][b][1])
                dp[a][b][1]=dp[b][a][1]=c;
        }
        dij();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值