bzoj 2763: [JLOI2011]飞行路线 spfa+dp
好久没有写题解,哈哈哈哈哈(已疯)
题目啦:
Description
Input
Output
Sample Input
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
Sample Output
HINT
对于30%的数据,2<=n<=50,1<=m<=300,k=0;
对于50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;
对于100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.
题目大意:
给一个图,给出起点 s 终点 t ,问可以免去 k 条路径的权值后的最短路。(不懂我也没办法)
思路:
刚开始看一脸萌逼,觉得乱搞bfs可以,然后就没有然后了,然后就默默看了题解 开始认真思考,what? 分层图?
表示不会,然后就只能滚回去想题,感觉可以dp,然后就又默默看了题解 开始认真思考。
用dist[i,j] 表示 从 s 到 i 用了 j 次 免费的最短路。
那么答案就是 ans=min(dist[t,i]) 0≤i≤k
状态转移方程?
可以转移到dist[i,j] 的要不就是 dist[lasti,j] (lasti 表示lasti 与i 有边 i 从 lasti 走过来的) 要不就是 dist[lasti,j-1]
可以很容易得到(好吧,我还是想了挺久的),dist[i,j]=min(dist[i,j],dist[lasti,j-1]+0,dist[lasti,j]+cost) (cost 为这条边的权值)
dist[lasti,j-1]+0这个表示这条边免费,那么用上次免费的加上0
dist[lasti,j]+cost这个表示这条边不免费,那么就要加上cost
方程在spfa找最短路的时候就用一个 for 更新一下 dist 数组
接下来就代码咯:
1 type 2 node=record 3 y:longint; 4 next:longint; 5 cost:int64; 6 end; 7 var 8 e:array[0..200010]of node;// 邻接表 9 q:array[0..3000000]of longint; //队列 10 dist:array[0..10010,-1..12]of int64; //dist 数组 11 first:array[0..10010]of longint; //邻接表的 12 v:array[0..10010]of boolean; 13 i,j,k:longint; 14 x,y,z:longint; 15 ans:longint; 16 tot:longint; 17 n,m:longint; 18 s,t:longint; 19 procedure add(x,y,z:longint); //建边 20 begin 21 inc(tot); 22 e[tot].next:=first[x]; 23 e[tot].y:=y; 24 e[tot].cost:=z; 25 first[x]:=tot; 26 end; 27 function min(a,b:longint):longint; 28 begin 29 if a<b then exit(a) else exit(b); 30 end; 31 procedure spfa(s:longint); 32 var head,tail,y,i,j,now:longint; 33 new:int64; 34 begin 35 for i:=1 to n do 36 begin 37 for j:=0 to k do 38 dist[i,j]:=maxlongint; //更新初值 39 v[i]:=false; 40 end; 41 for i:=0 to k do 42 dist[s,i]:=0; //s 到 s 的最短路是0 43 head:=1; 44 tail:=1; 45 q[1]:=s; 46 v[s]:=true; 47 while head<=tail do 48 begin 49 now:=q[head]; 50 i:=first[now]; 51 while i<>-1 do 52 begin 53 y:=e[i].y; 54 for j:=0 to k do 55 begin 56 if j<>0 then new:=min(dist[now,j-1],dist[now,j]+e[i].cost) else //j≠0 就是 方程 57 new:=dist[now,j]+e[i].cost; //j=0 就是 简单最短路 58 if dist[y,j]>new then 59 begin 60 dist[y,j]:=new; 61 if not v[y] then //入队 62 begin 63 v[y]:=true; 64 inc(tail); 65 q[tail]:=y; 66 end; 67 end; 68 end; 69 i:=e[i].next; 70 end; 71 inc(head); 72 v[now]:=false; 73 end; 74 end; 75 76 begin 77 read(n,m,k); 78 read(s,t); 79 inc(s); 80 inc(t); 81 for i:=1 to n do 82 first[i]:=-1; 83 for i:=1 to m do 84 begin 85 read(x,y,z); 86 inc(x); //我从1 开始所以 +1 87 inc(y); 88 add(x,y,z); 89 add(y,x,z); 90 end; 91 spfa(s); 92 ans:=maxlongint; 93 for i:=0 to k do 94 ans:=min(ans,dist[t,i]); //找最短咯 95 writeln(ans); 96 end.
然后就又水了一篇博客