景驰无人驾驶 1024 编程邀请赛 A.热爱工作的蒜蒜【二维最短路】

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

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

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

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

输入格式

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

接下来 TT 组数据。

每一组数据的第一行输入四个整数 n(2 \le n \le 100)n(2n100)m_1(0 \le m_1 \le 50)m1(0m150)m_2(0 \le m_2 \le 5000)m2(0m25000)L(1 \le L \le 10^8)L(1L108)

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

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

所有路径都是双向的

输出格式

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

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

思路:


观察到m1非常小,那么我们设定dist【i】【j】表示从起点走到了点i,经过了j条地下通道的情况下的最短路径长度。


那么Ans=Min(Dist【i】【j】-j,Ans);


过程维护一下即可。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node
{
    int from,to,next,w,flag;
}e[1500000];
struct node2
{
    int u,len;
}now,nex;
int n,m1,m2,L,cont;
int vis[150][350];
int dist[150][350];
int head[1500];
void add(int from,int to,int flag,int w)
{
    e[cont].flag=flag;
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
void SPFA()
{
    queue<node2>s;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=320;j++)
        {
            dist[i][j]=0x3f3f3f3f;
        }
    }
    dist[1][0]=0;
    now.len=0;
    now.u=1;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();s.pop();
        int u=now.u;
        int len=now.len;
        vis[u][len]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            int flag=e[i].flag;
            if(dist[v][len+flag]>=dist[u][len]+e[i].w)
            {
                dist[v][len+flag]=dist[u][len]+e[i].w;
                if(vis[v][len+flag]==0)
                {
                    vis[v][len+flag]=1;
                    nex.u=v;nex.len=len+flag;
                    s.push(nex);
                }
            }
        }
    }
    int output=0x3f3f3f3f;
    for(int i=0;i<=320;i++)
    {
        if(dist[n][i]<=L)
        output=min(output,dist[n][i]-i);
    }
    if(output==0x3f3f3f3f)output=-1;
    printf("%d\n",output);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cont=0;
        memset(head,-1,sizeof(head));
        scanf("%d%d%d%d",&n,&m1,&m2,&L);
        for(int i=1;i<=m1;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            add(x,y,1,1);add(y,x,1,1);
        }
        for(int i=1;i<=m2;i++)
        {
            int x,y,w;scanf("%d%d%d",&x,&y,&w);
            add(x,y,0,w);add(y,x,0,w);
        }
        SPFA();
    }
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值