Description
小C“五一”节参加了五星旅行社组织的一次外出旅游,这次旅游中,小C遇到一件非常有趣的事: 五星旅行社的导游小张有一根魔棒,这根魔棒在每一次的旅游中可以产生一次魔力(也只能产生一次魔力),这魔力可以使两个景点间的距离减成原来的一半。小C在“五一”节的这次旅游中,很有幸是小张导游作为他们的导游,小张当然也没有忘记带他的魔棒,因为他可以发挥魔棒的作用,使路程减少呢。这次旅游中,去了一个有N个景点的旅游区,这个旅游区只有一个入口,在景点编号为1的地方,一个出口,在景点编号为N的地方,景点编号为1,2,3,…,N。在入口处有一个N×N的数据阵,描述了景点间的距离,a[I,j]表示景点i到景点j的距离。因为小C的公司有急事要小C尽快回来,现在小C要用张导游的魔棒,使得从入口到出口的距离最短。现在我们也来编一个程序:求将哪一条边减半后使从顶点1到顶点N的最短路径长度最短,输出这个最短距离,如果找不到从1到N的路径,则输出 -1 。
Input
从文件中c.in读入数据,文件第一行是一个正整数N(3 ≤ N ≤ 50),表示共有N个点,接下来是一个N行N列的数据阵,a[I,j]的值表示顶点i到顶点j的长度。
Output
只有一个数就是将一条边长减半后的从1到N的最短路径长度,结果四舍五入到小数后两位,如果找不到从1到N的路径,则输出 -1 。
Sample Input
3
0 5 20
5 0 8
20 8 0
Sample Output
9.00
Source
elba
题解:
先看一下数据范围(3 ≤ N ≤ 50),而50^3=125000,所以本题考虑用Floyd算法来暴力枚举
因为本题有导游的魔(膜)棒,可以将某条道路折半(-1s),所以每条道路有折半和未折半两种情况。故从f[i,j]变为f[i,j,0/1](表示i顶点到j顶点,不折半 or 折半的最小路径,0为未折半,1为折半)
由此可以得出三条动态转移方程:①.打死不折半(用两条不折半的更新);②、③:我就折一个(分别用两条折半的来更新)
因为本题有不存在路的情况,所以判断输入为0,所以在输入为0时赋大值,最后判断即可
注:本题要求最后是四舍五入到小数后两位,而且奇数/2除不尽,所以要用real或double作输入和输出的整型
安利:
有一题和此题挺像的,也是有不同状态的,在这里推荐给大家
var
f:array[1..50,1..50,0..1]of real;
n,x,i,j,k:integer;//integer是为了跑题库的内存的(虽然还是跑不过c++...%>_<%)
function min(a,b:real):real;
begin
if a<b then exit(a);
exit(b);
end;
begin
read(n);
for i:=1 to n do
begin
for j:=1 to n do
begin
read(x);
if x=0 then//不存在就赋大值
begin
f[i,j,0]:=23333333;
f[i,j,1]:=23333333;
end
else
begin
f[i,j,0]:=x;
f[i,j,1]:=x/2;//折半
end;
end;
readln;//pascal的辛酸泪
end;
for k:=1 to n do
for i:=1 to n do
for j:=1 to n do
begin
f[i,j,0]:=min(f[i,k,0]+f[k,j,0],f[i,j,0]);//①
f[i,j,1]:=min(f[i,k,1]+f[k,j,0],f[i,j,1]);//②
f[i,j,1]:=min(f[i,k,0]+f[k,j,1],f[i,j,1]);//③
end;
if f[1,n,1]=23333333 then write(-1)//判断
else write(f[1,n,1]:0:2);//最短的一定是折过半的
end.