首先是稀疏图,不难想到dij+heap
观察题目可以知道,0<=k<=10;
所以比较裸的想法就是,d[i,j]表示已经免费了i条线路后到达j的最短路
容易得到
d[i,j]:=min(d[i,j],d[i-1,k]);
d[i,j]:=min(d[i,j],d[i,k]+w[k,j]);
然后在做dij在选择中间点的时候,我们穷举一下免费的线路数就可以了;
然后就要维护10个堆……
语言表述有点渣,具体还是看程序吧
1 const inf=2000000007; 2 type point=record 3 num,dis:longint; 4 end; 5 node=record 6 next,cost,point:longint; 7 end; 8 9 var edge:array[0..200010] of node; 10 heap:array[0..11,0..10010] of point; 11 d,where:array[0..11,0..10010] of longint; 12 h:array[0..11] of longint; 13 p:array[0..10010] of longint; 14 len,x,y,z,i,j,n,m,u,k,s,t:longint; 15 16 procedure swap(var a,b:point); 17 var c:point; 18 begin 19 c:=a; 20 a:=b; 21 b:=c; 22 end; 23 24 function min(a,b:longint):longint; 25 begin 26 if a>b then exit(b) else exit(a); 27 end; 28 29 procedure add(x,y,z:longint); 30 begin 31 inc(len); 32 edge[len].point:=y; 33 edge[len].cost:=z; 34 edge[len].next:=p[x]; 35 p[x]:=len; 36 end; 37 38 procedure sift(p,i:longint); 39 var j,x,y:longint; 40 begin 41 j:=i shl 1; 42 while j<=h[p] do 43 begin 44 if (j+1<=h[p]) and (heap[p,j].dis>heap[p,j+1].dis) then inc(j); 45 if heap[p,i].dis>heap[p,j].dis then 46 begin 47 x:=heap[p,i].num; 48 y:=heap[p,j].num; 49 where[p,x]:=j; 50 where[p,y]:=i; 51 swap(heap[p,i],heap[p,j]); 52 i:=j; 53 j:=i shl 1; 54 end 55 else break; 56 end; 57 end; 58 59 procedure up(p,i:longint); 60 var j,x,y:longint; 61 begin 62 j:=i shr 1; 63 while j>0 do 64 begin 65 if heap[p,i].dis<heap[p,j].dis then 66 begin 67 x:=heap[p,i].num; 68 y:=heap[p,j].num; 69 where[p,x]:=j; 70 where[p,y]:=i; 71 swap(heap[p,i],heap[p,j]); 72 i:=j; 73 j:=j shr 1; 74 end 75 else break; 76 end; 77 end; 78 79 begin 80 len:=-1; 81 fillchar(p,sizeof(p),255); 82 readln(n,m,k); 83 readln(s,t); 84 inc(s); //点序号都+1,习惯一点 85 inc(t); 86 for i:=1 to m do 87 begin 88 readln(x,y,z); 89 inc(x); 90 inc(y); 91 add(x,y,z); 92 add(y,x,z); 93 end; 94 for i:=1 to n do 95 if i<>s then 96 begin 97 for j:=0 to k do 98 d[j,i]:=inf; 99 end 100 else 101 for j:=0 to k do 102 d[j,i]:=0; 103 for i:=0 to k do 104 begin 105 for j:=1 to n do 106 begin 107 heap[i,j].num:=j; 108 heap[i,j].dis:=d[i,j]; 109 where[i,j]:=j; 110 end; 111 h[i]:=n; 112 end; 113 for i:=0 to k do 114 up(i,s); //起点不一定是0,要初始化堆,一开始这里被坑翻了 115 for u:=1 to n do 116 begin 117 for j:=k downto 0 do 118 begin 119 x:=heap[j,1].num; 120 y:=heap[j,h[j]].num; 121 if (h[j]=0) or (d[j,x]=inf) then continue; 122 where[j,y]:=1; //dij+heap比较重要的细节 123 swap(heap[j,1],heap[j,h[j]]); 124 dec(h[j]); 125 sift(j,1); //出堆,调整堆 126 i:=p[x]; 127 while i<>-1 do 128 begin 129 y:=edge[i].point; 130 if (j<>k) and (d[j+1,y]>d[j,x]) then //两种情况 131 begin 132 d[j+1,y]:=d[j,x]; 133 heap[j+1,where[j+1,y]].dis:=d[j+1,y]; 134 up(j+1,where[j+1,y]); 135 end; 136 if (d[j,y]>d[j,x]+edge[i].cost) then 137 begin 138 d[j,y]:=d[j,x]+edge[i].cost; 139 heap[j,where[j,y]].dis:=d[j,y]; 140 up(j,where[j,y]); 141 end; 142 i:=edge[i].next; 143 end; 144 end; 145 end; 146 writeln(d[k,t]); //肯定尽可能免费好啊 147 end.