bzoj 2763: [JLOI2011]飞行路线 spfa+dp

好久没有写题解,哈哈哈哈哈(已疯)

网址啦啦啦

题目啦:

Description

Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

Input

数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)
接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)
 

Output

 
只有一行,包含一个整数,为最少花费。

Sample Input

5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100

Sample Output

8

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.
bzoj 2763 

然后就又水了一篇博客

 

posted @ 2017-03-11 09:51  Bunnycxk  阅读(201)  评论(2编辑  收藏  举报