jzoj 1782. Travel

该博客介绍了如何解决一个有向图中限制第二种走法次数的最短路径问题。利用Floyd算法判断顶点间的可达性,并在不可达时将边长翻倍。随后通过SPFA和分层图方法找到满足条件的最短时间。当数据规模较小(n≤10, m≤10)时,可以直接求解;对于更大规模数据,博主建议进行预处理。" 94555079,7514112,Ubuntu上安装Elasticsearch踩坑及解决办法,"['Elasticsearch', 'Ubuntu', '系统配置', 'Java', '服务器管理']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

  给出一个有n个顶点m条边的有向图,对于一条边长度为len的边有两种走法。
  1、如果a和b可以互达,则走过这条边的时间为len
  2、如果a和b不可以互达,则走过这条边的时间为2*len
  现在给出一个k,问,从顶点1到顶点n,满足第二种走法不超过k次的最短时间是多少。

Input

  第一行有3个整数n,m,k(1<=n<=100,1<=m<=10000,0<=k<=10),表示有n个顶点,m条边。
  接下来有m行,每行有3个整数xi,yi,leni(1<=xi,yi<=n,1<=leni<=10000),表示长度为leni的有向边。
  注意,两个点可能有多条边连接。

Output

  一行一个整数,表示最短时间。
  如果没有满足题目条件的路径,则输出-1

Sample Input

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

Sample Output

20

Data Constraint

Hint

【数据约定】
  对于30%的数据n<=10,m<=10,
  对于100%的数据,如题目描述

题解

这道题看起来很难,实际上真的很(jian)难(dan)!

对于这题,因为数据范围很小,所以可以先用 Floyd 求是否连通,再把不连通的边 * 2 。在对于整个图跑一遍 SPFA和分层图,边跑变更新答案,就可以了。

分层图(拆点(二维dis))+spfa+floyd(预处理互达)

P.S:预处理可以用的遍历,也可以用的Floyd【数据过水,N才100】

CODE

uses math;
var
        n,m,t,i,j,k,ans:longint;
        p,d,map,f:array[0..1000,0..1000]of longint;
        bz:array[0..1000,0..1000]of boolean;
        x,y,len:array[0..2000]of longint;
procedure spfa();
var
        l,r,x,y,i,pp:longint;
begin
        fillchar(d,sizeof(d),0);
        fillchar(bz,sizeof(bz),false);
        fillchar(f,sizeof(f),127);
        f[1,0]:=0;bz[1,0]:=true;d[1,1]:=1;d[1,2]:=0;
        l:=1;r:=1;
        while l<=r do begin
                x:=d[l,1];
                y:=d[l,2];
                for i:=1 to n do
                        if map[x,i]<>0 then begin
                                if p[i,x]=1 then pp:=0 else pp:=1;
                                if f[i,y+pp]>map[x,i]+f[x,y] then begin
                                        f[i,y+pp]:=map[x,i]+f[x,y];
                                        if not bz[i,y+pp] then begin
                                                inc(r);
                                                d[r,1]:=i;
                                                d[r,2]:=y+pp;
                                                bz[i,y+pp]:=true;
                                        end;
                                end;
                        end;
                bz[k,j]:=false;
                inc(l);
        end;

end;
begin
        readln(n,m,t);
        for i:=1 to n do begin
                readln(x[i],y[i],len[i]);
                map[x[i],y[i]]:=len[i];
        end;
        for i:=1 to n do
                for j:=1 to n do
                        for k:=1 to n do
                                if (i<>j)and(i<>k)and(j<>k) then
                                        if map[i,k]+map[k,j]<map[i,j] then
                                                map[i,j]:=map[i,k]+map[k,j];
        fillchar(p,sizeof(p),1);
        for i:=1 to n do
                for j:=1 to n do
                        if (map[i,j]<>0)and(map[j,i]=0) then begin
                                map[i,j]:=map[i,j]*2;
                                //map[j,i]:=map[j,i]*2;
                                p[i,j]:=2;
                                //p[j,i]:=2;
                        end;
        spfa;
        ans:=maxlongint;
        for i:=0 to k do ans:=min(ans,f[n,i]);
        if ans=maxlongint then
                writeln(-1)
        else
                writeln(ans);
end.

P.S:不要开maxlongint(太大),会卡-1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值